.net的GC的理解


GC是.Net的垃圾收集器,可以进行内存资源的回收,程序员无需关心资源的回收,当一个对象没
有任何引用的时候就可以被回收了。一个对象可以被回收并不意味着一定会被立即回收,GC会选
择时机进行回收。可以调用GC.Collect()让GC立即回收。GC不能回收非托管资源,对于非托管
资源一般都实现了IDisposable接口,然后使用using关键字进行资源的回收。

void Func()
{
A a = new A();
B b = new B();
a.RefToB = b;
b.RefToA = a;
}

那么a和b会不会被GC回收?

GC管理对象不是用的COM的引用计数模式。事实上最初微软确实想用引用计数方式实现GC,这样的一个优势就是对象的析构时机是确定的,当引用计数为0时,对象会被析构,之后也不会再有任何代码能够再访问该对象,这是很理想的情况。但经过反复实验,这种方法被抛弃了。一个原因就是如上的例子,会导致对象无法释放。另一个重要原因就是应用计数的额外开销对高性能程序不可接受。尤其是在多线程情况下,因为.NET使用自由线程模型,多个线程可能同时访问一个对象,每一个引用计数的增减操作都不得不做线程同步。

.NET采用的GC模式是分代GC(Generational GC),堆空间按对象的生存期长短分成3代。新分配的对象在第0代,按地址顺序分配,当第0代的空间(约几百K)用光时,将程序里能引用到的对象移动到第1代,那么剩下的就是垃圾,第0代空间便可以重新用于分配。同理,第1代也按同样的逻辑运行,那么第2代里的对象将都是生存期很长的对象。由此可以推出如下几点:
1)对象的分配时间开销远小于C++的堆分配,但回收时间开销大于分配时间开销。
2)不会出现C++里的堆碎片过多的问题,有利于程序长时间运行。
3)循环引用的对象能够被正确回收。

那么再回答开始的问题,“什么情况下,对象会被GC回收?”正确答案是“当程序里没有对对象的活引用(Alive reference)时。”

原文地址:https://www.cnblogs.com/mxxblog/p/2396741.html