背景知识
跟踪收集器
全局记录对象之间的引用状态,执行时从一系列GC Roots的对象作为起点,从这些节点向下开始进行搜索所有的引用链。
当一个对象到GC Roots 没有任何引用链时,则证明此对象是不可用的。
图中,对象Object6、Object7、Object8虽然互相引用,但他们的GC Roots是不可到达的,所以它们将会被判定为是可回收的对象。
在Java语言中,可作为GC Roots 的对象包括:
虚拟机栈(栈帧中的本地变量表)中的引用对象。
方法区中的类静态属性引用的对象
方法区中的常量引用的对象
本地方法栈中JNI(即一般说的Native方法)引用的对象。
Java垃圾收集算法
1 标记-清除算法
标记-清除算法即(Mark-sweep)算法,分为“标记”和“清除”两个阶段:首先标记处所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
缺点:
一个是效率问题,标记和清除两个过程的效率都不高。
一个是空间问题,标记清除之后会产生大量的不连续的内存碎片,空间碎片太多可能会导致以后程序运行过程中需要废品较大对象时,无法找到足够的连续内存而不得不提前触发另一个垃圾回收动作。
发现GC Roots可达A和C。B不可达即被标记为待回收,然后清除被标记为待回收的对象。
2 复制算法
此算法是为了解决效率问题而出现的,它将可用内存按照容量划分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活的对象复制到另外一块,然后把已经使用过得内存一次清理掉。这样每次都对整个半区进行垃圾回收,内存分配时不需要考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可。
缺点:
将内存缩小为原来的一半。
A和C是还存活的对象,复制到左侧这半段。
先用使用左侧内存用完了,把存活对象复制到右侧内存,左侧一次释放。
3 标记-整理算法
标记-整理算法(Mark-Compact算法)复制收集算法再对象存活较高时就要进行较多的复制,效率会变低。而且需要浪费50%的空间。老年代一般不能直接采用该算法。
标记和“标记-清除算法”相同,但是之后并不是直接对可回收对象进行回收,而是让所有存活的对象移动到一端,然后直接清理掉端边界以外的内存。
好处:不会产生内存碎片
主要缺点:在标记-清除的基础上还需进行对象的移动,成本相对较高,
4 分代收集算法
商业虚拟机的垃圾收集都采用“分代收集”算法,根据对象存活周期不同,将内存划分为几块,一般把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来设置。
閱讀更多 明明如月學長 的文章