http://www.cnblogs.com/ywl925/p/3925637.html
一、如何确定对象是垃圾:
1、引用计数:当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象+1),但当一个对象的某个引用超过了生命周期或者被设置为一个新值时,对象的引用计数减1。
缺点:如果对象之间存在循环引用,会出现“应该被回收,但引用计数不为零”。如下面这段代码
public class Main { public static void main(String[] args) { MyObject object1 = new MyObject();//对象引用计数+1=1 MyObject object2 = new MyObject();//对象引用计数+1=1 object1.object = object2;//有引用连接至对象,对象计数+1=2 object2.object = object1;//有引用连接至对象,对象计数+1=2
object1 = null;//引用置为Null,引用计数-1=1
object2 = null;//引用置为Null,引用计数-1=1
}
}
class MyObject{ public Object object = null; }
2、遍历存活在堆栈和静态存储区中的引用,找到所有活的对象。对于发现的每个引用,必须追踪他所引用的对象,然后时此对象包含的所有引用。
二、如何将垃圾收集:
1.Mark-Sweep(标记-清除)算法:适用于少量垃圾
标记-清除算法实现起来比较容易,但是有一个比较严重的问题就是容易产生内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发新的一次垃圾收集动作。
2.Copying(复制)算法(停止-复制):适用于大量垃圾
运行高效且不容易产生内存碎片,但是却对内存空间的使用做出了高昂的代价,因为能够使用的内存缩减到原来的一半。
(不是在后台进行,垃圾回收动作发生的时候程序会被暂停。)
3.Mark-Compact(标记-整理)算法
4.Generational Collection(分代收集)算法:
它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。
目前大部分垃圾收集器对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间。
而由于老年代的特点是每次回收都只回收少量对象,一般使用的是Mark-Compact算法。
注意,在堆区之外还有一个代就是永久代(Permanet Generation),它用来存储class类、常量、方法描述等。对永久代的回收主要回收两部分内容:废弃常量和无用的类。