十种常见的垃圾回收器:Serial、SerialOld、ParallelScavenger、ParallelOld、ParNew、CMS、G1、ZGC、Shenandoah、Epsilon。
Serial、SerialOld、ParallelScavenger、ParNew、CMS在物理和逻辑上都分代。G1只在逻辑上分代,物理上不分代。ZGC、Shenandoah逻辑和物理上都不分代。Epsilon是jdk11提出debug使用的,不用考虑。
Serial、ParallelScavenger、ParNew是用于年轻代的,SerialOld、ParallelOld、CMS是用于老年代的。所以产生了垃圾回收器几种常见的组合:Serial+SerialOld、ParallelScavenger+ParallelOld、ParNew+CMS。
Serial:a stop-the-world,coping collector which uses a single GC thread
让所有的工作线程找到一个安全点,然后停止。所有的工作线程都停止这种行为叫做STW(stop-the-world),STW时,单线程的Serial开始工作,进行垃圾清理。当内存不断变大的时候,Serial的工作时间会变得很长,这样STW的时间就会很长,用户的响应时间很长,所以现在使用Serial的很少。
使用的是copy算法,把内存一分为二,将有用的拷贝到另外一半内存上,顺序排好。然后将有红色的一半内存区域全部清除。这种算法适合存活对象较少的情况,只扫描一次,不会产生碎片化,但是浪费空间。


SerialOld: a stop-the-world,mark-sweep-compact collector that uses a single GC thread
应用于老年代,单线程的。一样有STW。
使用的mark-sweep算法,把所有使用的标注出来,把那些未被标记的全部清除,这种需要扫描两次,第一次标记有用的,第二次清除未被标记的,容易产生碎片化。这种算法适合存活对象较多的情况。


ParallelScavenger(PS):a stop-the-world,coping collector which uses multiple GC thread
这个就是在Serial的基础上,使用多线程进行垃圾回收。
ParallelOld(PO):a stop-the-world,a compacting collector that uses a single GC thread
应用于老年代,多线程的。一样有STW。
使用的mark-compact算法,标价压缩,就是先把有用的都标记一下,然后边清理垃圾边整理。还是需要遍历两次,第一次标记,第二次清除和压缩,这种算法效率会低一些,但不会产生碎片化,也没有像拷贝算法一样浪费内存空间。

ParNew:a stop-the-world,coping collector which uses multiple GC thread
与ParallelScavenger的区别就是,PN能更好的和CMS配合使用,PN的响应时间优先,PS的吞吐量优先。
注:以上这几种都有一个共同的特点,垃圾回收线程和工作线程不能同时进行,就是垃圾回收时,所有的工作线程都要停止。因为这个就诞生了CMS,更好的缓解了STW时间过长的问题。
CMS:
The Concurrent Mark Sweep (CMS) collector is designed for applications that prefer shorter garbage collection pauses and that can afford to share processor resources with the garbage collector while the application is running.
CMS有4个主要阶段:初始标记阶段、并发标记阶段、重新标记阶段、并发清理阶段。
初始标记阶段:开始一个短暂的STW,然后进行初始标记,初始标记只标记根节点,所以这个STW时间很短。这个阶段是单线程的。
并发标记阶段:据说GC大部分时间都浪费在这,所以这一步是和工作线程同时运行的。一边产生垃圾,一边标记垃圾。
重新标记阶段:开始一个短暂的STW,把在并发标记阶段,工作线程产生的垃圾重新标记一下,这个STW时间也很短。这个阶段是多线程的。
并发清理阶段:工作线程和垃圾回收线程同时运行,把这个时候工作线程产生的垃圾叫做浮动垃圾,浮动垃圾就要等到下一次CMS清理了。

CMS是老年代的垃圾回收器,在老年代分配不下的时候,触发CMS。
CMS的最大问题:CMS会使内存碎片化,老年代产生了很多的碎片,然后从年轻代过来的对象无法找到空间,造成了promotion failed。这时候,CMS既没有机会进行垃圾回收,又放不下新来的对象,在这种情况下,CMS会调用SerialOld来进行垃圾回收。这是一件很恐怖的事情。
如何才能避免呢?降低触发CMS的阈值。
G1:
The Garbage First Garbage Collector (G1 GC) is the low-pause, server-style generational garbage collector for Java HotSpot VM. The G1 GC uses concurrent and parallel phases to achieve its target pause time and to maintain good throughput. When G1 GC determines that a garbage collection is necessary, it collects the regions with the least live data first (garbage first).
G1在逻辑上分代,在物理上不分代。G1引入了分而治之的思想,把内存分为一个一个的小块(region)。每个region逻辑上属于下面四种分代中的一种。
四种分代:
a.Old区:老对象
b.Survivor区:存活对象
c.Eden区:新生对象
d.Humongous区:大对象,如果这个对象特别大,可能会跨两个region。

G1的显著特点:
a.并发收集
b.压缩空间不会延长GC的暂停时间
c.更易预测GC的暂停时间
d.适合不需要很高吞吐量的场景。
CMS与G1在并发标记上的算法都采用的是三色标记,但是在针对可能被误标的情况,CMS采取了IncrementalUpate算法,G1采用了STAB算法。
注:CMS本身的原因,并不是任何一个版本JDK的默认垃圾回收器。JDK8的默认垃圾回收器是PS+PO,JKD9的默认垃圾回收器是G1。G1的响应时间比PS+PO短,但G1的吞吐量比PS+PO降低了。
ZGC:
逻辑和物理上都不分代,在并发标记的时候采用的是颜色指针。42位记录地址,4位代表状态,18位的空闲。

关于垃圾回收器和内存大小的参考如下表:


2249

被折叠的 条评论
为什么被折叠?



