日期:2014-05-20  浏览次数:20880 次

obj=null;是否能让对象立刻释放,是否能加快对象释放,是否有必要加上?
我这个喜欢闭门造车,所以很多论点都有可能是错误,于是放在这里和大家一起商讨一下。如果对各位造成什么误导的话,个人不请求原谅,你们爱报复就报复,爱打击就打击,我不嫌弃臭鸡蛋,当然更喜欢鲜花。。。好了,客套就到此为至。以下说说主题。

 昨天和一群友讨论内存回收的问题。突然有位自称IBM+移动的JAVA群友说在使用完对象后整个=null;这样对象可以加快翻译。。。并且经过IBM小组的严格测试。。。
汗一把,怀疑是难免的。后来看到坛子里也有讨论析构函数的,于是也发个帖。。

首先以,是否能让对象内存立刻回收 展开说法。。
  
  个人认为这是错误的:
设置对象null时执行,设置对象null只是段开了内存对象与引用句柄之间的引用关系,只是把引用转了个位,并没有让对象为null
翻译对象主分两块,一为非托管对象,二为托管对象。
先以非托管对象为例:这个我简单测试为"设置对象null只是段开了内存对象与引用句柄之间的引用关系"是正确的。。
测试Code
C# code

 static void OpenConnection(SqlConnection conn)
        {
            if (conn.State != ConnectionState.Open)
                conn.Open();
        }

        static void TestUnManager()
        {
            try
            {
                for (int i = 0; i < 10; i++)
                {
                    SqlConnection conn = new SqlConnection("server=20080827-1517; User ID=sa;Password=cherry; database=InforSys; min pool size=2; max pool size=3");

                    TimeSpan bts = DateTime.Now.TimeOfDay;
                    OpenConnection(conn);
                    TimeSpan ets = DateTime.Now.TimeOfDay;
                    TimeSpan ts = bts - ets;
                    Console.WriteLine(ts);
                    //conn.Close();
                    conn = null;
                    Thread.Sleep(1000);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }



基本来说,如果按照对象为null 的话,连接肯定是不存在的。实事是,连接在请求第5个的时候出exception,抛链接池已满。。


托管资源是否为一样?其实这个一般比较难测试,因为垃圾回收机制一般在内存进缺的时候会比较勤快,而且在申请内存方面也是很麻烦,
于是测试环境我为所有能关的服务都关了,内存为2G当前使用情况为581M的情况下测试,这样或许不会让垃圾回收器觉醒过来。。
但是内存申请也是个麻烦事,一开始使用StringBuilder来划内存,当然,效果肯定是没有的,后来只有采用粗鲁的手段从数据库大表里填充数据集。。这方法其实也很默哀,如果有更好方法的朋友可以告诉偶一下。。。。

测试CODE

C# code


 static void TestManager()
        {
            for (int i = 0; i < 10; i++)
            {
                GetTable();                
            }
        }

        static void GetTable()
        {
          
            using (SqlConnection conn = new SqlConnection("server=20080827-1517; User ID=sa;Password=cherry; database=InfoSys; min pool size=20; max pool size=100"))
            {
                SqlCommand cmd = new SqlCommand("select * from gtl_comp", conn);
                using (SqlDataAdapter da = new SqlDataAdapter())
                {
                    DataTable dt = new DataTable();
                    da.SelectCommand = cmd;
                    da.Fill(dt);

                    dt = null;//这分两个,一个有,一个没有
                }
            }         
           
        }



分两种情况都执行了一下,发现内存的消耗情况基本相同,有dt=null的有时反而会多占用一点。。。
基本认为有没有是一个样,不能立刻对象释放。。(同在内存使用量不是很大的情况下)


以上测试比较简单,但我个人认为=null;是不能加快对象释放的。


最后一个为,是否有必要加上,受一坛子的帖启发来测试的。

MSDN原话:
 
垃圾回收器使用名为“终止队列”的内部结构跟踪具有 Finalize 方法的对象。每次您的应用程序创建具有 Finalize 方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。



关键的是垃圾回收器在运行的时候会释放怎么样的对象?在我的理解里一直为当该对象没有任何引用时,垃圾回收器就运行该对象的析构,释放对象。。。

测试CODE
C# code

 public class Test
    {
        private string name;
        public Test(string name)
        {
            this.name = name;
            StringBuilder sb = new StringBuilder(10240000);
            for (int i = 0; i < 102400; i++)
                sb.Append(name+i);
        }

        ~Test()
        {
            Console.WriteLine(name+"执行到析构");
        }

 static void Main(string[] args)
        {
            //TestUnManager();
            //TestManager();
            NotSetNull();
            SetNull();
           
        }

        static void NotSetNull() 
        {
            for (int i = 0; i < 100; i++)
            {
                Test t = new Test("ojek"+i);
            }
        }

        static void SetNull()
        {
            for (int i = 100; i < 200; i++)
            {
                Test t = new Test("ojek" + i);
                t = null;
            }
        }
    }