CSDN博客

img Bluclyf

GC机制对非托管资源的回收

发表于2004/7/3 13:00:00  1353人阅读

对于托管资源,.net的GC机制可以很好的回收无用的垃圾。然而对于非托管资源,必须自己手动释放掉其资源。什么是非托管资源呢?例如文件访问、网络访问等,这些资源都需要手动清除。难道真的是这样吗?我们来做个实验。建立一个类

public class FileGC
{
?private Stream m_srFile;
?public FileGC()
?{
??m_srFile=File.Open(".//1.txt",FileMode.OpenOrCreate,FileAccess.Write);
?}
}
这个类很简单,实例化时创建或打开1.txt文件。


建立一个窗体,上面添加一个按钮。窗体初始化时添加如下事件
private void Form1_Load(object sender, System.EventArgs e)
{
?FileGC f=new FileGC();
}

按钮中添加如下事件。
private void btGC_Click(object sender, System.EventArgs e)
{
?GC.Collect();
}

这样,当窗体初始化时就会产生一个无用的资源FileGC f,为了验证1.txt是否被打开,你可以尝试删除掉目录下的1.txt。此时你会发现会提示文件正在被访问。当你按下按钮,程序强制进行GC操作,此时f对象被销毁。其实此时的m_srFile对象也被销毁了,为了验证,尝试删除1.txt。成功。
等一等,这里有个冲突不是说GC机制对于非托管资源无法释放吗?那m_srFile对象对于1.txt的连接是怎么关闭的呢?

理论上应该是f对象被清除,然而由于m_srFile对象使用的是非托管资源而无法被清除。可是事实却是m_srFile对象被清除了。难道Stream有自己清除的功能?光猜想是不够的。使用ILDasm打开mscorlib.dll文件,这个文件是.NET Framework类的主要配件,mscorlib.dll包含了大部分我们使用的类。把它拆了看看吧。

打开后看到一个树形目录System->System.IO->Stream看看这个类的声明。
.class public abstract auto ansi beforefieldinit Stream
?????? extends System.MarshalByRefObject
?????? implements System.IDisposable
extends System.MarshalByRefObject
说明该类派生自System.MarshalByRefObject
implements System.IDisposable并使用了System.IDisposable接口。

察看整个Stream的IL没有发现回收文件句柄的操作。是否我们找错了方向,看看File.Open打开文件使用了类型。
System.IO.File.Open看看它的代码。
.method public hidebysig static
??????? class 'System.IO'.'FileStream'
??????? 'Open'(string 'path',
?????????????? valuetype 'System.IO'.'FileMode' 'mode',
?????????????? valuetype 'System.IO'.'FileAccess' 'access',
?????????????? valuetype 'System.IO'.'FileShare' 'share') cil managed
原来返回类型是FileStream,而不是Stream。让我们来看看FileStream的类型。

首先看看类型的定义
class public auto ansi beforefieldinit 'FileStream' extends 'System.IO'.'Stream'
可以看到由于FileStream继承自Stream,因此在File.Open打开后可以转换为Stream。向下看,你会看到Finalize方法。对就是它,当GC发现它无用,执行清除其占用内存前所作的操作。名曰析构函数,这里的情况可和C++有类似的地方。

打开这个方法。你会发现一条重要语句
callvirt?? instance void 'System.IO'.'FileStream'::'Dispose'(bool)
原来在执行GC操作前执行了Dispose方法。这下我们明白了,原来.net已经为我们做好了这些事情。同样我也察看了其他一些资源比如网络等,发现.net已经为我们做好了这些操作。虽然是非托管资源,可是大家完全不用担心资源泄漏问题。除非你使用的是API函数打开的,那么你就必须自己写好Finalize方法。
本人能力很浅,错误之处还忘高手予以批评指正。也欢迎对于.net运行环境感兴趣的志同道合的朋友共同讨论问题。
联系方式:
QQ:85627584
邮箱:fjl716@163.com

0 0

相关博文

我的热门文章

img
取 消
img