目录
1.1 标记-清除算法(CMS收集器-Concurrent Mark Sweep)
1.2 复制算法(serial new,parallel new和parallel scanvage收集器)
1.3 标记-整理算法(parallel scanvange gc和Serial old收集器)
一、垃圾收集算法
1.1 标记-清除算法(CMS收集器-Concurrent Mark Sweep)
算法分为"标记"和"清除"阶段,首先标记处需要回收的对象,标记完成后统一回收所有被标记的对象。它是最基础的收集算法,其他收集算法都是在它的基础上改进得到。
缺点:
1、效率不足;
2、空间问题(标记清除会产生大量不连续的碎片,空间碎片太多可能会导致程序运行过程需要分配较大的对象时候,无法找到足够连续内存而不得不提前触发一次垃圾收集,比较适合老年代)。
1.2 复制算法(serial new,parallel new和parallel scanvage收集器)
解决效率问题,但是内存缩小原来的一般。它是将内存分为大小相同的两(A/B)块,每次使用其中的一块,当A使用完后,就将还存活的对象复制到B中,然后再把A空间一次清理掉,每次的内存回收都是对内存区间的一半进行回收。适合新生代。
改进:
新生代都是朝生夕死,并不需要很大的内存,因此可以将内存分为一块较大的Eden区和两块较小的Suvivor空间;每次使用Eden和其中一块Survivor。当回收的时候,将Eden和Survivor中还活着的对象一次性地复制到另一块Survivor空间上,最后清理掉Eden和刚才使用过的Suevivor空间。其中Eden和Suevivor的大小比例是8:1。缺点是需要老年代进行分配担保,如果第二块的Survovor空间不够的时候,需要对老年代进行垃圾回收,然后存储新生代的对象,这些新生代当然会直接进入来老年代。
1.3 标记-整理算法(parallel scanvange gc和Serial old收集器)
解决空间问题,但是整理会消耗一定的时间。分为"标记"和"整理"两个阶段,首先标记处所有需要回收的对象,让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。适合老年代。
1.4 分代收集算法
分代收集算法就是针对不同的年老代/新生代/持久代采用不同的收集算法,
新生代采用复制算法(改进版);
年老代采用标记-清除/标记-整理算法;
持久代(方法区,在Java 8中,永久代被彻底移除,取而代之的是另一块与堆不相连的本地内存——元空间)
二、GC是什么时候触发的
由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。
2.1 Scavenge GC(死嘎问机)
新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,把尚且存活的对象移动到Survivor(色外围儿---幸存)区,对Eden区域进行GC,清除非存活对象,。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。
2.2 Full GC(佛儿)
对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于Full GC的调节。有如下原因可能导致Full GC:
a) 年老代(Tenured)被写满;
b) 持久代(Perm)被写满;
c) System.gc()被显示调用;
d) 上一次GC之后Heap的各域分配策略动态变化;