有关于.net的垃圾回收的一个问答

在微软新闻组看到的一个QA 摘要如下:

Q:在 .net 2.0 下,对象 object.Dispose() 之后,是否还需要 object=null 

这个概念我一直模糊,
1.1 下面好像 object=null好像不能释放内存还增加内存。

2.0 下, object=null 到底能不能释放内存 

A:

Dispose 方法一般会调用 GC.SuppressFinalize,因此在您使用 Dispose 之后,系统已经认为该对象已经释放,也不会尝试再次处置该对象。

您需要区分“对象资源被回收”和“对象被回收”两个不同的概念。

例如,f 是一个 Form 类型的对象,则在内存中,f 本身是一个托管指针,您如果使用了 Dispose 方法,那么 f 指向的 Form 对象中的资源将被释放,也就是说 f 现在指向的 Form 对象已经是无效的,甚至可能指向已经被别的对象占用的空间。

但是 f 自身仍然占有一个指针的空间(内容是原来的 Form 对象的地址),即使您使用 f = null,那么 f 只是自身的内容变成 null。f 对象本身仍然占用了一个指针的空间。

您永远无法控制一个托管指针本身的释放(也就是说您无法尝试通知垃圾回收器把 f 自身的空间处置)。垃圾回收器会自动地在 f 对象脱离生存期(如离开了声明的方法,或所在的类实例被处置)后回收该空间。

一般程序上所说的用 null 来释放空间是这样的:

object obj = XXXX;
obj = null;

这里如果把 obj 设置为 null,那么 obj 原来指向的那块空间可能就变成无人可访问了。这时候垃圾回收程序会回收那块空间,但是同样不会回收 obj 本身的空间。

将处置后对象设置为 null 一般来说在程序使用上有一定意义,因为您可以通过和 null 作比较方便的判断某个对象是否有效。如果不设置为 null,而您又处置了对象,那么如果您只是使用 obj != null 的方式来判断,之后对 obj 作某些操作,那么会引发 ObjectDisposedException

 

 你好,不知道您是否学过 C++?如果学过的话也许您能够比较好的理解这个问题。
> >
> > Object a = new Object();
> >
> > 此时 a 是一个指针,我们假设他占用 4 个字节(内存 1),而 Object 是一个对
象,可能会占用 32 个字节(内存 2)。a 的 4 个字节的内容就是那个 Object 对象
所在的
> > 位置。
> >
> > a = null;
> >
> > 此处将 a 设置为 null,只是更改了 a 自身的值(把 a 自己的 4 个字节全部置
> > 0),但是结果是使原来 a 指向的内容(内存 2)无法访问。垃圾回收器会看到
这一情况,然后回收那个不可访问的对象。同时如果继续使用 a,那么代码运行的时候
会检查到您试图获取位置 0 中
> > 对象的内容,而位置 0 表示空位置,因此会提示您 NullReferenceException。
> >
> > 如果用
> >
> > a.Dispose();
> >
> > 那么程序会手动清理干净内存 2 中的一些资源(比如图像资源)。但是此时 a 的
内容没有变化,指向的位置还是内存 2。这时就出现一个问题,a 无法在被使用(因为
其中的内容已经被
> > 处置)。这时候如果您继续使用 a,那么系统不会检测到
> > NullReferenceException,但是因为实际上里面的内容已经被释放而用作他用,
在尝试读取的时候系统会引发 ObjectDisposedException,也就是检测到您尝试读取已
经释放掉的位置的内容。

 

a是引用型变量, 是占用4字节空间的指针, 指针指向 Object 在内存中实际位置的首地址.

当a中含有非托管资源时, =null后, GC只会回收占用的托管资源, 不能释放非托管资源.
如果要释放全部资源, 就要先调用Dispose方法释放非托管资源, 然后再由GC回收托管资源. 

 

如果您的类成员中有实现 System.IDisposable 接口,那么您如果使用代码分析(如 FxCop),则代码分析器会提示您为类本身实现 System.IDisposable 接口,并且用规范的格式实现 Dispose() 方法。

实现 Dispose() 方法如我在上一帖中所示,一般需要如下设定:
a.. 提供一个虚(或重写)的、受保护的 Dispose(bool disposing) 方法,分别在其中释放托管资源和非托管资源。
b.. 提供公开的 Dispose(),该方法调用 Dispose(true) 以及 GC.SuppressFinalize(this) 方法。
c.. 重写析构方法,并在其中调用 Dispose(false) 方法。
所有托管对象中的托管资源都会在对象被终结(析构方法,在 C++ 中为 Finalize)时回收,所以如果您的类中没有一些非托管的资源,那么无需实现上面的方法。

一般来说,.NET Framework 基本库中本身定义 Dispose() 的对象,其中都包括非托管资源(如文件流、窗体等,都包括一些系统级别的非托管资源),因此如果自己定义的类型中创建了这种对象,那么您应当提供上面的方法以便于用户请求回收资源。或者至少,您应当在析构方法中释放所有创建的资源。否则可能会造成资源泄露。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值