Java GC基本算法

转自:http://www.blogjava.net/showsun/archive/2011/07/21/354745.html

1、引用计数(referencecounting)

原理:此对象有一个引用,则+1;删除一个引用,则-1。只用收集计数为0的对象。

缺点:无法处理循环引用的问题。如:对象A和B分别有字段b、a,令A.b=B和B.a=A,除此之外这2个对象再无任何引用,那实际上这2个对象已经不可能再被访问,但是引用计数算法却无法回收他们。

2、复制(copying)

原理:把内存空间划分为2个相等的区域,每次只使用一个区域。垃圾回收时,遍历当前使用区域,把正在使用的对象复制到另外一个区域。

优点:不会出现碎片问题。

缺点:1、暂停整个应用。2、需要2倍的内存空间。

3、标记-清扫(Mark-and-sweep)---sun前期版本就是用这个技术。

原理:对于“活”的对象,一定可以追溯到其存活在堆栈、静态存储区之中的引用。这个引用链条可能会穿过数个对象层次。第一阶段:从GCroots开始遍历所有的引用,对有活的对象进行标记。第二阶段:对堆进行遍历,把未标记的对象进行清除。这个解决了循环引用的问题。

缺点:1、暂停整个应用;2、会产生内存碎片。

4、标记-压缩(Mark-Compact)自适应

原理:第一阶段标记活的对象,第二阶段把为标记的对象压缩到堆的其中一块,按顺序放。

优点:1、避免标记扫描的碎片问题;2、避免停止复制的空间问题。

具体使用什么方法GC,Java虚拟机会进行监视,如果所有对象都很稳定,垃圾回收器的效率低的话,就切换到“标记-扫描”方式;同样,Java虚拟机会跟踪“标记-扫描”的效果,要是堆空间碎片出现很多碎片,就会切换回“停止-复制”模式。这就是自适应的技术。

5、分代(generationalcollecting)-----J2SE1.2以后使用此算法

原理:基于对象生命周期分析得出的垃圾回收算法。把对象分为年轻代、年老代、持久代,对不同的生命周期使用不同的算法(2-3方法中的一个即4自适应)进行回收。

如上图所示:为Java的各代分布图

年轻代(young)

分为3个区。一个Eden区,2个survivor区。大部分对象在Eden中生成。当Eden区满时,还存活的对象将被复制到survivor区。当该survivor区满时,此区的存活对象被复制到另外一个survivor区,当第2个survivor区也满时,该区还存活的对象将被复制到年老区(tenured)。

年老代(tenured)

存放从年轻代(young)复制过来的对象。

持久代(perm)

用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著的影响,但是有些应用可能动态生成或者调用一些class。持久代大小通过-XX:MaxPermSize=N进行设置

Thinkinginjava给javagc取了一个罗嗦的称呼:“自适应、分代的、停止-复制、标记-扫描”式的垃圾回收器。

导致Gc的情况:

1、tenured被写满

2、perm被写满

3、System.gc()的显式调用。

4、上一次GC之后heap的各域分配策略动态变化。

相关推荐