高吞吐量可以最高效率利用CPU时间,适合在后台运算而不需要太多交互的任务,-XX:MaxGCPauseMillis(控制最大垃圾收集停顿时间),-XX:GCTimeRatio(直接设置吞吐量大小)。
4.4 Serial Old收集器Serial收集器的老年代版本,单线程收集,使用"标记-整理"算法;
client模式下的虚拟机使用;
作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure的时候使用。
4.5 Parallel Old收集器Parallel Scavenge收集器的老年代版本,使用多线程和"标记-整理算法"
4.6 CMS收集器以获取最短回收停顿时间为目标的收集器,基于"标记-清除"算法,整个过程分为4个步骤:
初始标记(CMS initial mark)
并发标记(CMS concurrent mark)
重新标记(CMS remark)
并发清除(CMS concurrent sweep)
其中初始标记、重新标记两个步骤任然需要"Stop The World"。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。
优点:并发收集、低停顿
缺点:
对CPU资源非常敏感
无法处理浮动垃圾(Floating Garbage)
会产生垃圾碎片
4.7 G1收集器基于"标记-整理"算法,可以非常精确地控制停顿,即能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。G1收集器可以实现在基本不牺牲吞吐量的前提下完成低停顿的内存回收,这是由于它能够极力地避免全区域的垃圾收集,G1将整个Java堆(包括新生代、老年代)划分为多个大小固定的独立区域(Region),并且跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域(Garbage First)。区域划分及有优先级的区域回收,保证了G1收集器在有限的时间内可以获得最高的收集效率。
5 内存分配与回收策略 5.1 对象优先在Eden分配大多数情况下,对象在新生代Eden区分配。当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。
5.2 大对象直接进入老年代所谓大对象就是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串及数组。虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代中分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存拷贝。
注意:PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效。
5.3 长期存活的对象将进入老年代虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次Minor GC后任然存活,并且能被Survivor容纳的话,将被移动到Survivor空间,并将对象年龄设为1。对象在Survivor区中每熬过一次Minor GC,年龄就增加1岁,当年龄增加到一定程度(默认15岁),就会被晋升到老年代中,可通过参数-XX:MaxTenuringThreshold来设置。
5.4 动态对象年龄判定为了能更好地适应不同程序的内存状况,虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。
5.5 空间分配担保前面提到过,新生代使用复制收集算法,但为了内存利用率,只使用其中一个Survivor空间来作为轮换备份,因此当出现大量对象在Minor GC后仍然存活的情况时(最极端就是内存回收后新生代中所有对象都存活),就需要老年代进行分配担保,让Survivor无法容纳的对象直接进入老年代。老年代要进行这样的担保,前提是老年代本身还有容纳这些对象的剩余空间,一共有多少对象会活下来,在实际完成内存回收之前是无法明确知道的,所以只好取之前每一次回收晋升到老年代对象容量的平均大小值作为经验值,与老年代的剩余空间进行比较,决定是否进行Full GC来让老年代腾出更多空间。