JVM垃圾回收

垃圾可分为:年青代,年老代,持久代。

1. Young(年轻代)
分为三个分区,一个Eden区,两个Survivor区。大部分对象在Eden中生成,Eden满,还存活的对象被复制到其中一个survivor区。当这个survivor满时,存活的对象被复制到另一个Survivor区。当这个survivor区也满了得时候,从第一个survivor区复制过来的,且还存活的对象将被复制到“老年区(Tenured)”。被复制到老年区的只有从另一个survivor区复制过来的对象。survivor区总有一个是空得。

2.Tenured(年老代)
存放从年轻代存活的对象。一般年老带存放的都是生命期较长的对象。

3.Perm(持久代)
用于存放静态文件,如JAVA类,方法等。持久代对垃圾回收没有显著影响。

大部分对象被分配到Eden space,并且大部分对象在该区域被释放。当进行minor GC的时候,VM会把剩下的没有释放的对象从Eden space移动到其中一个survivor space中。此外,vm会把长期存活在survivor spaces里面的对象移动到老年代的Tenured space中。 当Tenured generation填满后,会产生一次FULL GC。 Full GC比较慢,因为回收的内容包括了所有的live状态的对象。

GC的类型:Scavenge GC 和Full GC

Scavenge GC:一般情况下,新对象生成,申请Eden空间失败时触发。将Eden区进行GC,清除非存活对象,并把尚且存活的对象移动到survivor区,然后整理Survivor的两个区。

Full GC: 对整个堆进行整理,包括Young, Tenured 和 perm。
如下原因可导致full GC:Tenured被写满,Perm区域被写满,System.gc()被显示调用。

垃圾收集器
负责收集年轻代的垃圾收集器:serial,ParNew,ParallelScavenge
负责收集老年代的垃圾收集器:CMS,Serial Old, Parallel Old
同时收集年轻代和年老代的垃圾收集器:Garbage First(G1)

其中,serial Old能与serial, ParNew, ParallelScavenge三款垃圾收集器组合。
CMS只能与serial,ParNew组合,且会添加serial-old。在CMS出现concurrent Mode Failure时用serial-old代替CMS进行Full GC。

Parallel Old只能与ParallelScavenge搭配。

serial是一个单线程收集器。“单线程”分两部分理解。第一,只有一条线程负责垃圾回收。第二,垃圾回收时,必须暂停其他所有的工作线程。
优点:简单高效。在单CPU环境中,Serial收集器由于没有线程交互的开销,能获得最高的单线程收集效率。在用户桌面应用中,分配给虚拟机管理的内存不会太大,收集停顿时间完全可以控制在几十毫秒, 只要不频繁发生,停顿完全可以接受。因此在client模式下地虚拟机Serial收集器是一个不错的选择。

ParNew收集器:是Serial收集器的多线程版本。使用多条线程进行垃圾回收,其余行为与Serial收集器完全相同。

ParallelScavenge收集器:也是并行的多线程收集器。该收集器的目标是达到一个可控制的吞吐量(吞吐量 = 运行用户代码时间/(运行用户代码时间+垃圾收集时间))。
停顿时间越短越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

可以用控制最大垃圾收集停顿时间的 -XX : MaxGCPauseMillis参数以及直接设置吞吐量大小的参数-XX: GCTimeRatio参数来精确控制吞吐量。

注意:MaxGCPauseMills越小不代表垃圾回收的速度越快,缩短GC停顿时间是通过减少吞吐量以及减少新生代空间来换取的。减少新生代空间即原本收集500M大小变为300M;减少吞吐量——原来每10秒收集一次,每次停顿100ms,现在改为5秒一次,每次停顿70ms。虽然暂停时间减少了,但吞吐量下降了。
通过-XX:UseAdaptiveSizePolicy虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。自适应调整策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别。

年轻代收集器使用的算法都是拷贝算法。

Serial Old收集器:Serial收集器的老年代版本。标记-清除算法

Parallel Old收集器:在Parallel Old出现之前,ParallelScavenge收集器只能和serial - old搭配使用。由于Serial-old收集器在服务器端应用性能上的“拖累”,使得Parallel Scavenge收集器未必能再整体应用上获得吞吐量的最大化的效果。由于单线程的老年代收集中无法利用服务器多CPU的处理能力,因此这种组合的吞吐量甚至不一定有ParNew+CMS的组合“给力”。
Parallel old + Parallel Scavenge的组合在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑。

CMS: concurrent Mark Sweep收集器是一种以获取最短停顿时间为目标的收集器。适合重视服务的响应速度,希望停顿时间短的应用。

分为4个步骤
1. 初始标记:只标记GC Root能直接关联到的对象,需要暂停其他线程,但时间很短。
2. 并发标记:进行GC Root的tracing过程。这段时间比较长,但不暂停其他线程。与用户线程并发执行。
3. 重新标记:需要暂停其他线程,为了修正并发标记期间因用户继续运作而导致标记产生变动的那一部分对象的标记,停顿时间比初始标记长,但远小于并发标记时间。
4.并发清除:不需要暂停用户线程。

缺点:
1. 对CPU资源非常敏感。
2. 无法处理浮动垃圾,可能出现“Concurrent Mode Failure”。
    CMS并发清理阶段用户线程还在运行着,伴随程序运行自然会产生新的垃圾,这部分垃圾出现在标记过之后,CMS无法处理它们,只能留待下一次GC时再清理掉。这部分垃圾称为“浮动垃圾”。
    由于垃圾收集阶段用户线程还需要运行,那就还需要预留足够的内存空间给用户线程使用。因此CMS不能等到老年代几乎用完再收集,需要预留一部分空间提供并发收集时的程序运作使用。 可通过-XX: CMSInitialtingOccupancyFraction来设置触发垃圾回收的百分比。 要是CMS运行期间预留内存无法满足程序需要,会出现一次“Concurrent Mode Failure”,这时虚拟机启用后备方案:临时启动Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间久很长了。

3. CMS采用标记—清除算法实现,收集结束会出现大量的空间碎片。对大对象分配带来很大麻烦。


猜你喜欢

转载自mir-tempo.iteye.com/blog/2230729