一、首先看两个衡量GC性能的指标
1、吞吐量
该指标表示程序占用CPU执行的时间(包含分配内存的时间,不包括GC时间)占总时间的百分比。
2、停顿时间
该指标表示程序不响应的时间(正在进行垃圾回收)。
吞吐量越大而停顿时间越小,表示GC性能越好。对于不同的应用有不同的需求,例如对于很多web应用来说,停顿时间太长会使用户明显感觉到卡顿,很影响用户体验。
二、于是,通常通过调整以下参数来获得需要的程序性能
1、指定最大停顿时间,表示能容忍的GC时停止应用的持续时长(单位:ms)。
-XX:MaxGCPauseMillis=xxx
2、指定GC比率,表示能够接受的GC时间占总时间的比例
-XX:GCTimeRatio=xx
例如-XX:GCTimeRatio=19,GC占用时间为1/(1+19)=1/20即5%,表示GC占用执行时间的比例为5%
因而,垃圾收集器通常都要考虑到这些因素以满足不同的应用场景。
三、分代垃圾收集
考虑一个细致的问题:一个对象Object什么时候会被认为是垃圾?
在通过任何一个指针都无法访问到的情况下,即不可达。
垃圾回收最直接的方式便是迭代遍历每个可达对象,最后剩下的便是垃圾对象。然而,对于大的应用来讲这么做是可怕的,因为这么做的GC时间与对象数量近似成正比,庞大应用有太多的存活数据,会导致GC的时间相当长。
这也是大多数垃圾收集器都采用分代回收策略的原因,这是应用经验论建立的一种弱代假设。弱代假设表明:大多数对象的存活时间都是很短的。
基于这种经验性的观察,JVM将垃圾回收分为两个部分,年轻代和老年代,进行分代回收。大量的对象在年轻代死亡,能够被快速回收,其它存活到一定age的对象则进入老年代。年轻代和老年代收集相互独立。
绝大多数对象都在Eden区域分配。两个Survivor,任意时刻总有一个是空的,作为Eden空间存活对象转移的目的地。另一个作为下一次拷贝使用,minor GC之后还存活的对象被转移到另一个Survivor区,两个Survivor区的存活对象这样来回拷贝,直到他们存活“年龄”足够大而被拷贝到老年代。
其实年轻代Yong这样划分也是基于一定考虑,为方便垃圾回收时进行整理,也就是说在清理完垃圾对象之后将存活对象进行整理,这样就不会出现大量的内存碎片。