java 垃圾回收步步深入02----判断对象是否已死
1.引用计数法
堆中每一个对象都有一个引用计数。当新创建一个对象,或者有变量被赋值为这个对象的引用,则这个对象的引用计数加1;当一个对象的引用超过生存期或者被设置一个新的值时,这个对象的引用计数减1。当对象的引用计数变为0时,就可以被当作垃圾收集。
在引用的时候+1,在释放的时候-1,在发现计数值为0的时候这块内存就不再需要了。但是为什么很多地方都不会使用引用计数?最致命的问题引用计数只是一个充分非必要条件,也就是说:引用计数为0的时候内存不会再被使用,而不会再被使用的内存引用计数不一定为0。最简单的例子就是循环引用了:如果A引用了B,同时B又引用了A,那么这两对象的计数永远也都不会是0了(那么这两个对象占用的空间也当然用于不会释放)
这种方法的好处是垃圾收集较快,适用于实时环境。缺点是这种方法无法监测出循环引用。例如对象A引用对象B,对象B也引用对象A,则这两个对象可能无法被垃圾收集器收集。因此这种方法是垃圾收集的早期策略,现在很少使用。
2.跟踪法
这种方法把每个对象看作图中一个节点,对象之间的引用关系为图中各节点的邻接关系。垃圾收集器从一个或数个根结点遍历对象图,如果有些对象节点永远无法到达,则这个对象可以被当作垃圾回收。
容易发现,这种方法可以检测出循环引用,避免了引用计数法的缺点,较为常用。
跟踪法又称为“标记并清除”策略。基本思想是从根对象开始遍历整个对象图,仍然被引用的对象打上标记,遍历结束后,没有被打上标记的对象就可以清除。记录标记的策略可以在对象本身记录或者通过位图来记录。
跟踪收集器通常使用两种策略来实现:
1.压缩收集器:遍历的过程中如果发现对象有效,则立刻把对象越过空闲区滑动到堆的一端,这样堆的另一端就出现了一个大的连续空闲区,从而消除了堆碎片。
2.拷贝收集器:堆被分为大小相等的两个区域,任何时候都只使用其中一个区域。对象在同一个区域中分配,直到这个区域被耗尽。此时,程序执行被中止,堆被遍历,遍历时被标记为活动的对象被拷贝到另外一个区域。这种做法用称之为“停止并拷贝”。
这种做法的主要缺点是:太粗暴,要拷贝就都拷贝,粒度太大,整体性能不高。因此就有了更先进的“按代收集的收集器”