GC:简单的说,GC的回收算法是建立在新对象生存期短的假设下的(这个假设是很靠谱的,考虑一下我们写的代码就可以明白,最外层的代码总是被用很久,一个for里面的变量往往用过就抛弃了)。所以它会优先回收那些比较新的对象占用的内存。
更具体一些,它采用一种被称为代龄算法的回收算法,默认将所有堆中的对象分成0,1,2三个代龄,代龄越大的对象越老,越可能被继续使用,刚分配来的都为0代。每个代龄对象的总空间都有一个阈值,CLR会根据GC的执行情况动态调整这个阈值。当0代对象占用的空间超过阈值的时候,GC会启动来回收内存,先回收0代的空间,然后提升0代为1代,如果1代也满了则回收1(否则就结束了),依此类推。
上面描述的是一个宏观的过程,既考虑整体上托管堆是如何被分配和回收的。让我们再考虑具体一个对象的分配和回收。假设这个对象叫faint(^_^)。首先,faint在托管堆被分配了,这时候它为0代。很不幸,在faint还没有提升到1代的时候,它就被抛弃了,成了一个无根的对象。这时候GC老大起来收内存了,faint当然没有逃脱老大锐利的眼神。关键时刻来临了,老大会问它一个生死攸关的问题(其实不是即时判断的,而是事先用一个结构保存好了的),你的Finalize方法是不是原来的Object.Finalize()(不好意思说的那么恶心,Finalize是对象回收时被调用的一个方法,在Object类中有默认的实现,如果faint的祖先中有一个重写了Finalize方法,这个方法就不算是原有的Object.Finalize方法了),如果是,那么当场被干掉,不复存在;如果不是,faint会依然被放在堆中,在下一次GC启动的时候再被干掉(早死和晚死的问题)。故事写的很不好,需要强调的是,如果一个类在继承的结构中被重载过Finalize方法,它不会在两次GC启动后被回收。
注意:GC只能回收托管堆中的资源。其他一些非托管资源,比如文件资源,缓冲区,互斥体之类,无法通过GC自动回收。必须通过开发人员自己编程实现对其的回收
===================================================
其实知道GC,是在刚接触Java的时候。当时只知是Java底层的机制和操作系统协作 去实现回收,并不愿了解具体的过程。
今天课上老师问起,大家都怔住了...
嗯,要学的还真不少!~