zoukankan      html  css  js  c++  java
  • 全局静态集合类型的变量的垃圾你给我去死!!!!(本文知识有误,请等待8.12晚上的反思)

    反思--------不怕丢脸,就怕没收获

    原来,这篇文章居然成了个笑话唉。
    事大概是这么个事哈,我看http://bbs.csdn.net/topics/80471342,大概知道了静态变量的回收是有限制滴。
    而我刚好遇到这么个业务,我现在想自己做一个MMO游戏的服务端,因为服务端需要实时模拟每一个客户端的记录 。所以毫无疑问这个变量要是一个集合,并且一直在内存中。
    所以我的代码是这么写的 
    Public static Dictionary<int,Actor> dcActors = new Dictionary<int,Actor>();
    可突发奇想,是不是静态集合的类型的变量内存回收会有限制呢??于是写了下面两段代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            public static void Main(string[] args)
            {
                Run();
    
                Wait();
            }
    
            public static void Run()
            {
                B B = new B();
    
                for (int i = 0; i < 10000000; i++)
                {
                    B.dcA.Add(i, new A());
                }
             
                B.dcA.Clear();
                Console.WriteLine("清掉了");
                GC.Collect();
    
            }
    
            public static void Wait()
            {
                Console.Read();
                Console.Read();
                Console.Read();
                Console.Read();
            }
    
        }
    
        class B
        {
            public   Dictionary<int, A> dcA = new Dictionary<int, A>();
        }
    
    
    
        class A
        {
            public string str = "水水水水水水水水水水水水水水水水水水水水水水水水";
    
         
        }
    
    
    }
    非静态变量
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            public static void Main(string[] args)
            {
                Run();
    
                Wait();
            }
    
            public static void Run()
            {
                B B = new B();
    
                for (int i = 0; i < 10000000; i++)
                {
                    B.dcA.Add(i, new A());
                }
             
                B.dcA.Clear();
                Console.WriteLine("清掉了");
                GC.Collect();
    
            }
    
            public static void Wait()
            {
                Console.Read();
                Console.Read();
                Console.Read();
                Console.Read();
            }
    
        }
    
        class B
        {
            public static  Dictionary<int, A> dcA = new Dictionary<int, A>();
        }
    
    
    
        class A
        {
            public string str = "水水水水水水水水水水水水水水水水水水水水水水水水";
    
         
        }
    
    
    }
    静态变量

    然后  ,非静态变量的那段代码在哈希表被清掉之后,我截图看是这样滴。

    而,静态变量的哈希表被情调后,内存检测工具显示是这样滴。

    所以,我就信任了这个 内存检测工具.....  唉.......。

    而我用资源管理器里的东西看内存,发现,两个代码都是由600多M(填充1000W个实体类) 掉到300多M(全部清空)。

    而我在代码中的类型A里添加析构函数检测,发现两个代码在清空的时候,1000W个类A都被销毁了

    所以我的教训是

    1:在没有使用到一些特殊的诸如UI,IO,数据库,图片,事件=....  等地方的时候,几乎可以完全相信.NET的GC的威力。只要你没有某些代码没有死守着对象不放,GC是一定可以找到垃圾并回收的。静态变量当然在此列

    2:一些个工具什么的其实未必要那么信任。自己写的代码检测才是王道

    3:有问题就要拿出来大家一起讨论,不怕丢脸,但就怕没收获

    问题

    众所周知,C#比起C++ C 等语言来说,最大的好处就是几乎不用管理内存,也就是不用处理‘垃圾’,会有GC自动来清扫。但我有一个疑惑就在于,全局静态集合型变量的垃圾谁来收?

    代码

    如上图,定义了一个  哈希表dcA,初始给其填充   1000万个 对象A。执行该程序,会发现1000W个对象填充到内存里,内存会非常大,打开资源管理器会发现,这内存占了大约600M的样子。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            public static void Main(string[] args)
            {
                Run();
    
                Wait();
            }
    
            public static void Run()
            {
            
                for (int i = 0; i < 10000000; i++)
                {
                    B.dcA.Add(i, new A());
                }
    
                B.dcA.Clear();
    
                Console.WriteLine("清除了");
            }
    
            public static void Wait()
            {
                Console.Read();
                Console.Read();
                Console.Read();
                Console.Read();
            }
    
        }
    
        class B
        {
            public static  Dictionary<int, A> dcA = new Dictionary<int, A>();
        }
    
        class A
        {
            public string str = "水水水水水水水水水水水水水水水水水水水水水水水水";
        }
    }
    可接下来让我蛋疼的问题是,清除掉了哈希表中的这1000W个对象。内存......  内存居然还是600多M,居然一点都没变。

     

    内存检测工具来了


     

     

    图中说的啥

    第一图非常明显的告诉我,内存占用者就是那个明明已经为空的 键值对大哥。一下占了几百兆。
    第二张图 告诉我,这个变量不是GC回收的对象,离 GC  root 还有一步之远。

    所以,祭出GC了

    尼玛内存一点都没减少,有种可能是GC还没出动,所以我把代码改一下,在  B.dcA.Clear(); 收加上  GC.Collect();
    可是,这行代码居然一点作用都没有。


    你说,全局静态集合类型的静态变量的垃圾谁来收呢??难倒一直在内存中呆着直到死???

    感谢    imfunny 给出的一个小解决方案让我更加了解了GC的机制。
    简单的来说我的问题就是:
    假如某个变量是非静态变量集合,比如public List<A> aList =new List<A>();  
    我们给这个aList填充1千万个对象然后清空,内存会马上会被回收。
    但如果是public static List<A> aList =new List<A>();  
    我们给这个静态的aList填充1千万个对象然后清空,内存就丝毫不会变。
    而在我的业务需求中,我要求在内存中在我需要的时候一直驻留着List<A>,当其中的某个A的实例不要了我清掉,
    这个被我清掉的的A的实例会被回收掉。
    我之前的想法是通过静态的共有的集合类型,即public static List<A> aList =new List<A>();  
    但后来发现我怎么清空都没用,我业务需求又注定不能用 aList=null,这样的机制
    所以,我想了一个折中的办法,即加入这个aList属于  B类型,那么我再创建一个C类型,在C类型中写一个单键
    类,有且仅有一个B的静态实例。这样的话我就能实现我的业务需求了
    29楼的大侠给出了我的这种思想的代码,各位前往围观啊


    答案:


     29楼的大侠给出了我的问题的答案。各位可以参考一下 这篇博客 http://www.cnblogs.com/bayonetxxx/archive/2009/06/02/1494728.html。即WeakReference 类的使用。嘿嘿

  • 相关阅读:
    install_bugzilla
    R610 & R710 网卡问题
    总结开发者在合作过程中的典型交流方式
    vnc报错 font catalog is not properly configured
    eclipse插件安装
    extjs 点击链接到另一个页面 并激活另一个页面的指定tab
    centos c++ 找不到头文件mysql.h
    升级struts 2
    oracle 删除用户报错
    mysql 创建用户及授权
  • 原文地址:https://www.cnblogs.com/MySilverlight/p/3251320.html
Copyright © 2011-2022 走看看