Java垃圾收集算法

背景知识

Java垃圾收集算法

跟踪收集器

全局记录对象之间的引用状态,执行时从一系列GC Roots的对象作为起点,从这些节点向下开始进行搜索所有的引用链。

当一个对象到GC Roots 没有任何引用链时,则证明此对象是不可用的。

图中,对象Object6、Object7、Object8虽然互相引用,但他们的GC Roots是不可到达的,所以它们将会被判定为是可回收的对象。

Java垃圾收集算法

在Java语言中,可作为GC Roots 的对象包括:

  1. 虚拟机栈(栈帧中的本地变量表)中的引用对象。

  2. 方法区中的类静态属性引用的对象

  3. 方法区中的常量引用的对象

  4. 本地方法栈中JNI(即一般说的Native方法)引用的对象。


Java垃圾收集算法

1 标记-清除算法

标记-清除算法即(Mark-sweep)算法,分为“标记”和“清除”两个阶段:首先标记处所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

缺点:

  1. 一个是效率问题,标记和清除两个过程的效率都不高。

  2. 一个是空间问题,标记清除之后会产生大量的不连续的内存碎片,空间碎片太多可能会导致以后程序运行过程中需要废品较大对象时,无法找到足够的连续内存而不得不提前触发另一个垃圾回收动作。

Java垃圾收集算法

发现GC Roots可达A和C。B不可达即被标记为待回收,然后清除被标记为待回收的对象。

Java垃圾收集算法

2 复制算法

此算法是为了解决效率问题而出现的,它将可用内存按照容量划分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活的对象复制到另外一块,然后把已经使用过得内存一次清理掉。这样每次都对整个半区进行垃圾回收,内存分配时不需要考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可。

缺点:

将内存缩小为原来的一半。

Java垃圾收集算法

A和C是还存活的对象,复制到左侧这半段。

Java垃圾收集算法

先用使用左侧内存用完了,把存活对象复制到右侧内存,左侧一次释放。

3 标记-整理算法

标记-整理算法(Mark-Compact算法)复制收集算法再对象存活较高时就要进行较多的复制,效率会变低。而且需要浪费50%的空间。老年代一般不能直接采用该算法。

标记和“标记-清除算法”相同,但是之后并不是直接对可回收对象进行回收,而是让所有存活的对象移动到一端,然后直接清理掉端边界以外的内存。

好处:不会产生内存碎片

主要缺点:在标记-清除的基础上还需进行对象的移动,成本相对较高,

Java垃圾收集算法

Java垃圾收集算法

4 分代收集算法

商业虚拟机的垃圾收集都采用“分代收集”算法,根据对象存活周期不同,将内存划分为几块,一般把Java堆分为新生代老年代,这样可以根据不同年代的特点采用最适当的收集算法。

新生代每次垃圾收集时都有大量对象死去,只有少量存活,那就选用复制算法。

老年代因为对象存活率很高,建议使用“标记-清理”或者“标记-整理”算法进行回收。


拓展知识

Java堆中各代分布

Java垃圾收集算法

Young:主要是用来存放新生的对象。

Old

:主要存放应用程序中生命周期长的内存对象。

Permanent:是指内存的永久保存区域,主要存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域. 它和和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。

GC 和 Full GC 有什么区别

GC(或Minor GC):收集 生命周期短的区域(Young area)。

Full GC (或Major GC):收集生命周期短的区域(Young area)生命周期比较长的区域(Old area)对整个堆进行垃圾收集。

GC 效率也会比较高,我们要尽量减少 Full GC 的次数。

当显式调用System.gc()时,gc does a full collection(both young generation and tenured generation).,说明执行的是Full GC。

Minor GC后,Eden是空的吗?

正如前面讲的,新生代一般采用复制算法。

Minor GC会把Eden中的所有活的对象都移到Survivor区域中,如果Survivor区中放不下,那么剩下的活的对象就被移到Old generation 中。

所以Minor GC后Eden是空的。

常见的内存泄露错误

常见的内存泄露为java.lang.OutOfMemoryError的错误。

这种错误又分两种:java.lang.OutOfMemoryError: Java heap space和java.lang.OutOfMemoryError: PermGen space

错误的原因可能是程序问题,也可能是是JVM参数配置问题引起的。

若是参数问题,前者可以同过配置-Xms和-Xmx参数来设置,

而后者可以通过配置 -XX:PermSize和-XX:MaxPermSize来设置。


分享到:


相關文章: