JVM1.6 GC详解

前言 

JVM GC是JVM的内存回收算法,调整JVM GC(Garbage Collection),能够极大的减小因为GC工做,而致使的程序运行中断方面的问题,进而适当的提升Java程序的工做效率。可是调整GC是以个极为复杂的过程,因此咱们要了解JVM内存组成,回收算法,对象分配机制。java

 

JVM 堆内存组成

Java堆由Perm区和Heap区组成,Heap区由Old区和New区(也叫Young区)组成,New区由Eden区、From区和To区(Survivor)组成。算法


Eden区用于存放新生成的对象。Eden中的对象生命不会超过一次Minor GC。数组

Survivor Space  有两个,存放每次垃圾回收后存活的对象,即图的S0和S1。服务器

Old Generation  Old区,也称老生代,主要存放应用程序中生命周期长的存活对象多线程

 

JVM初始分配的内存由-Xms指定,JVM最大分配的内存由-Xmx指定。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减小堆直到 -Xms的最小限制。所以服务器通常设置-Xms、-Xmx相等以免在每次GC 后调整堆的大小。并发

-XX:NewRatio= 参数能够设置Young与Old的大小比例,-server时默认为1:2,若是过小,会使大对象直接分配到old区去,增大major collections的执行的次数,影响性能。
-XX:SurvivorRatio= 参数能够设置Eden与Survivor的比例,默认为1:8,Survivio大了会浪费,若是小了的话,会使一些大对象在作minor gc时,直接从eden区潜逃到old区,让old区的gc频繁。这个参数保持默认就行了,通常状况下,对性能影响不大。jvm

启动后可经过jmap –heap [pid]查看。
 
因为堆的总体大小是固定的,young generation越大,tenured generation越小,越会增长major collections的执行的次数。因此最佳的选择是由对象的生命周期分布所决定。

 

New区的Collector

 

一、  串行GC(Serial Copying)性能

     client模式下的默认GC方式,也可以使用-XX:+UseSerialGC指定。spa

二、  并行回收GC(Parallel Scavenge)
     server模式下的默认GC方式,也可用-XX:+UseParallelGC强制指定。线程

     采用PS时,默认状况下JVM会在运行时动态调整Eden:S0:S1的比例,若是不但愿自动调整可使用-XX:-UseAdaptiveSizePolicy参数,内存分配和回收的算法和串行相同,惟一不一样仅在于回收时为多线程。

三、  并行GC(ParNew)

     CMS GC时默认采用,也能够采用-XX:+UseParNewGC指定。内存分配、回收和PS相同,不一样的仅在于会收拾会配合CMS作些处理。

 

Old区的几种Collector

一、  串行GC(Serial MSC)

     client模式下的默认GC方式,可经过-XX:+UseSerialGC强制指定。每次进行所有回收,进行Compact,很是耗费时间。

二、  并行GC(Parallel MSC)(备注,吞吐量大,可是gc的时候响应很慢)

    server模式下的默认GC方式,也可用-XX:+UseParallelGC=强制指定。能够在选项后加等号来制定并行的线程数。

三、  并发GC(CMS)线上环境采用的GC方式,也就是Realese环境的方式。(备注,响应比并行gc快不少,可是牺牲了必定的吞吐量)

     使用CMS是为了减小GC执行时的停顿时间,垃圾回收线程和应用线程同时执行,可使用-XX:+UseConcMarkSweepGC=指定使用,后边接等号指定并发线程数。CMS每次回收只停顿很短的时间,分别在开始的时候(Initial Marking),和中间(Final Marking)的时候,第二次时间略长。具体CMS的过程能够参考相关文档。JStat中将Initial Mark和Remark都统计成了FGC。

CMS一个比较大的问题是碎片和浮动垃圾问题(Floating Gabage)。碎片是因为CMS默认不对内存进行Compact所致,能够经过-XX:+UseCMSCompactAtFullCollection。

 

整体来说,Old区的大小较大,垃圾回收算法较费时间,致使较长时间的应用线程中止工做,并且须要进行Compact,因此不该该出现较多Major GC。Major GC的时间经常是Minor GC的几十倍。JVM内存调优的重点,减小Major GC 的次数,由于为Major GC 会暂停程序比较长的时间,若是Major GC 的次数比较多,意味着应用程序的JVM内存参数须要进行调整。

 

JVM内存分配策略

 

1. 对象优先在Eden分配


若是Eden区不足分配对象,会作一个minor gc,回收内存,尝试分配对象,若是依然不足分配,才分配到Old区。


2.大对象直接进入老年代


大对象是指须要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串及数组,虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代中分配。这样作的目的是避免在Eden区及两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效,

3.长期存活的对象将进入老年代

在经历了屡次的Minor GC后仍然存活:在触发了Minor GC后,存活对象被存入Survivor区在经历了屡次Minor GC以后,若是仍然存活的话,则该对象被晋升到Old区。
虚拟机既然采用了分代收集的思想来管理内存,那内存回收时就必须能识别哪些对象应当放在新生代,哪些对象应放在老年代中。为了作到这点,虚拟机给每一个对象定义了一个对象年龄(Age)计数器。若是对象在Eden出生并通过第一次Minor GC后仍然存活,而且能被Survivor容纳的话,将被移动到Survivor空间中,并将对象年龄设为1。对象在Survivor区中每熬过一次Minor GC,年龄就增长1岁,当它的年龄增长到必定程度(默认为15岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值,能够经过参数-XX:MaxTenuringThreshold来设置。

4.动态对象年龄断定


为了能更好地适应不一样程序的内存情况,虚拟机并不老是要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,若是在Survivor空间中相同年龄全部对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就能够直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。


5.Minor GC后Survivor空间不足就直接放入Old区

6.空间分配担保

在发生Minor GC时,虚拟机会检测以前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,若是大于,则改成直接进行一次Full GC。若是小于,则查看HandlePromotionFailure设置是否容许担保失败;若是容许,那只会进行Minor GC;若是不容许,则也要改成进行一次Full GC。大部分状况下都仍是会将HandlePromotionFailure开关打开,避免Full GC过于频繁。

 

JVM GC组合方式

 

 

如何监视GC

1.概览监视gc。

   jmap -heap [pid] 查看内存分布

   jstat -gcutil [pid] 1000 每隔1s输出java进程的gc状况

2.详细监视gc。

   在jvm启动参数,加入-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:./gc.log。

   输入示例:

  

 [GC [ParNew: 11450951K->1014116K(11673600K), 0.8698830 secs] 27569972K->17943420K(37614976K), 0.8699520 secs] [Times: user=11.28 sys=0.82, real=0.86 secs]

   表示发生一次minor GC,ParNew是新生代的gc算法,11450951K表示eden区的存活对象的内存总和,1014116K表示回收后的存活对象的内存总和,11673600K是整个eden区的内存总和。0.8699520 secs表示minor gc花费的时间。

   27569972K表示整个heap区的存活对象总和,17943420K表示回收后整个heap区的存活对象总和,37614976K表示整个heap区的内存总和。

[Full GC [Tenured: 27569972K->16569972K(27569972K), 180.2368177 secs] 36614976K->27569972K(37614976K), [Perm : 28671K->28635K(28672K)], 0.2371537 secs]

  表示发生了一次Full GC,整个JVM都停顿了180多秒,输出说明同上。只是Tenured: 27569972K->16569972K(27569972K)表示的是old区,而上面是eden区。

 

更多能够参考 阿里分享的ppt sunjdk1.6gc.pptx

相关文章
相关标签/搜索