对于.Net CLR的垃圾自动回收,这两日有兴致小小研究了一下。查阅资料,写代码测试,发现不研究还罢,越研究越不明白了。在这里sban写下自己的心得以抛砖引玉,望各路高手多多指教。
近日浏览Msdn2,有一段很是费解,引于此处:
实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。
原文:http://msdn2.microsoft.com/zh-cn/library/0s71x931(VS.80).aspx
英文:把zh-cn替成en-us。此文档对应.net2.0,把VS.80替成VS.90可查看.net3.5最新文档。两者无甚差别,可见自.net1.1之后,垃圾回收机制没有改变。
据上文引用,关于GC的二次回收,sban作图一张,如下:
为了验证GC对含有终结器对象的两次回收机制,我写了一个例子测试,代码如下:
using
System;
using System.Threading;
using System.IO;
using System.Data.SqlClient;
using System.Net;
namespace Lab
{
class Log
{
public static readonly string logFilePath = @" d:/log.txt " ;
public static void Write( string s)
{
Thread.Sleep( 10 );
using (StreamWriter sw = File.AppendText(logFilePath))
//此处有可能抛出文件正在使用的异常,但不影响测试
{
sw.WriteLine( " {0}/tTotalMilliseconds:{1}/tTotalMemory:{2} " , s,
DateTime.Now.TimeOfDay.TotalMilliseconds, GC.GetTotalMemory( false ));
sw.Close();
}
}
}
class World
{
protected FileStream fs = null ;
protected SqlConnection conn = null ;
public World()
{
fs = new FileStream(Log.logFilePath, FileMode.Open);
conn = new SqlConnection();
}
protected void Finalize()
{
fs.Dispose();
conn.Dispose();
Log.Write( " World's destructor is called " );
}
}
class China : World
{
public China()
: base ()
{
}
~ China()
{
Log.Write( " China's destructor is called " );
}
}
class Beijing : China
{
public Beijing()
: base ()
{
}
using System.Threading;
using System.IO;
using System.Data.SqlClient;
using System.Net;
namespace Lab
{
class Log
{
public static readonly string logFilePath = @" d:/log.txt " ;
public static void Write( string s)
{
Thread.Sleep( 10 );
using (StreamWriter sw = File.AppendText(logFilePath))
//此处有可能抛出文件正在使用的异常,但不影响测试
{
sw.WriteLine( " {0}/tTotalMilliseconds:{1}/tTotalMemory:{2} " , s,
DateTime.Now.TimeOfDay.TotalMilliseconds, GC.GetTotalMemory( false ));
sw.Close();
}
}
}
class World
{
protected FileStream fs = null ;
protected SqlConnection conn = null ;
public World()
{
fs = new FileStream(Log.logFilePath, FileMode.Open);
conn = new SqlConnection();
}
protected void Finalize()
{
fs.Dispose();
conn.Dispose();
Log.Write( " World's destructor is called " );
}
}
class China : World
{
public China()
: base ()
{
}
~ China()
{
Log.Write( " China's destructor is called " );
}
}
class Beijing : China
{
public Beijing()
: base ()
{
}