读书人

深入JVM系列(2)之GC机制、收集器与G

发布时间: 2013-10-22 16:17:03 作者: rapoo

深入JVM系列(二)之GC机制、收集器与GC调优

一、回顾JVM内存分配?

需要了解更多内存模式与内存分配的,请看?深入JVM系列(一)之内存模型与内存分配

?

?

1.1、内存分配:

1、对象优先在EDEN分配
2、大对象直接进入老年代?
3、长期存活的对象将进入老年代?
4、适龄对象也可能进入老年代:动态对象年龄判断



动态对象年龄判断:

虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,当Survivor空间的相同年龄的所有对象大小总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中指定的年龄

深入JVM系列(2)之GC机制、收集器与GC调优

?

1.2、总结一下:

?

1、对象优先在Eden分配,这里大部分对象具有朝生夕灭的特征,Minor GC主要清理该处
2、大对象(占内存大)、老对象(使用频繁)

3、Survivor无法容纳的对象,将进入老年代,Full GC的主要清理该处

?

二、JVM的GC机制?

JVM有2个GC线程

?

?

第一个线程负责回收Heap的Young区
第二个线程在Heap不足时,遍历Heap,将Young 区升级为Older区

?


Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能

?

?

?

2.1、堆内存GC?

?????? JVM(采用分代回收的策略),用较高的频率对年轻的对象(young generation)进行YGC,而对老对象(tenured?generation)较少(tenured?generation 满了后才进行)进行Full GC。这样就不需要每次GC都将内存中所有对象都检查一遍。

?

?

2.2、非堆内存不GC?

????? GC不会在主程序运行期对PermGen Space进行清理,所以如果你的应用中有很多CLASS(特别是动态生成类,当然permgen space存放的内容不仅限于类)的话,就很可能出现PermGen Space错误。

?

?

2.3、内存申请、对象衰老过程?

2.3.1、内存申请过程?

?

  1. JVM会试图为相关Java对象在Eden中初始化一块内存区域;
  2. 当Eden空间足够时,内存申请结束。否则到下一步;
  3. JVM试图释放在Eden中所有不活跃的对象(minor collection),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
  4. Survivor区被用来作为Eden及old的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区;
  5. 当old区空间不够时,JVM会在old区进行major collection;
  6. 完全垃圾收集后,若Survivor及old区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现"Out of memory错误";
?

2.3.2、对象衰老过程?
  1. 新创建的对象的内存都分配自eden。Minor collection的过程就是将eden和在用survivor space中的活对象copy到空闲survivor space中。对象在young generation里经历了一定次数(可以通过参数配置)的minor collection后,就会被移到old generation中,称为tenuring。

GC触发条件

?

GC类型触发条件触发时发生了什么注意查看方式YGCeden空间不足

清空Eden+from survivor中所有no ref的对象占用的内存
将eden+from sur中所有存活的对象copy到to sur中
一些对象将晋升到old中:
??? to sur放不下的
??? 存活次数超过turning threshold中的
重新计算tenuring threshold(serial parallel GC会触发此项)

重新调整Eden 和from的大小(parallel GC会触发此项)

全过程暂停应用
是否为多线程处理由具体的GC决定jstat gcutil?
gc logFGCold空间不足
perm空间不足
显示调用System.GC, RMI等的定时触发
YGC时的悲观策略
dump live的内存信息时(jmap dump:live)清空heap中no ref的对象
permgen中已经被卸载的classloader中加载的class信息

如配置了CollectGenOFirst,则先触发YGC(针对serial GC)
如配置了ScavengeBeforeFullGC,则先触发YGC(针对serial GC)全过程暂停应用
是否为多线程处理由具体的GC决定

是否压缩需要看配置的具体GCjstat gcutil?
gc log



?


permanent generation空间不足会引发Full GC,仍然不够会引发PermGen Space错误。

三、GC监视、收集器与GC调优?

?

3.1、监视JVM GC?

?

?

首先说一下如何监视JVM GC,可以用JDK中的jstat工具,也可以在java程序启动的opt里加上如下几个参数(注:这两个参数只针对SUN的HotSpotVM):

?

?

[java]?view plaincopy?
  1. -XX:-PrintGCPrintmessagesatgarbagecollection.Manageable.????
  2. -XX:-PrintGCDetailsPrintmoredetailsatgarbagecollection.Manageable.(Introducedin1.4.0.)????
  3. -XX:-PrintGCTimeStampsPrinttimestampsatgarbagecollection.Manageable(Introducedin1.4.0.)???



?

当把-XX:-PrintGCDetails加入到javaopt里以后可以看见如下输出:

?

[GC[DefNew:34538K->2311K(36352K),0.0232439secs]45898K->15874K(520320K),0.0233874secs]
[FullGC[Tenured:13563K->15402K(483968K),0.2368177secs]21163K->15402K(520320K),[Perm:28671K->28635K(28672K)],0.2371537secs]

?

他们分别显示了JVM GC的过程,清理出了多少空间。第一行GC使用的是‘普通GC’(MinorCollections),第二行使用的是‘全GC’(MajorCollections)。他们的区别很大,在第一行最后我们可以看见他的时间是0.0233874秒,而第二行的FullGC的时间是0.2371537秒。第二行的时间是第一行的接近10倍,也就是我们这次调优的重点,减少FullGC的次数,以为FullGC会暂停程序比较长的时间,如果FullGC的次数比较多。程序就会经常性的假死。

注:

?

GC信息的格式

?

?

[GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]
<collector> GC为minor收集过程中使用的垃圾收集器起的内部名称.
<starting occupancy1> young generation 在进行垃圾收集前被对象使用的存储空间.
<ending occupancy1> young generation 在进行垃圾收集后被对象使用的存储空间
<pause time1> minor收集使应用暂停的时间长短(秒)?
<starting occupancy3> 整个堆(Heap Size)在进行垃圾收集前被对象使用的存储空间
<ending occupancy3> 整个堆(Heap Size)在进行垃圾收集后被对象使用的存储空间
<pause time3> 整个垃圾收集使应用暂停的时间长短(秒),包括major收集使应用暂停的时间(如果发生了major收集).

GC信息的选项


-XX:+PrintGCDetails 显示GC的详细信息
-XX:+PrintGCApplicationConcurrentTime 打印应用执行的时间
-XX:+PrintGCApplicationStoppedTime 打印应用被暂停的时间



?

3.2、collector收集器的种类???

???

?

GC在 HotSpot VM 5.0里有四种:

incremental (sometimes called train) low pause collector已被废弃,不在介绍.

?

类别serial collectorparallel collector
(?throughput collector?)concurrent collector
(concurrent low pause collector)介绍单线程收集器
使用单线程去完成所有的gc工作,没有线程间的通信,这种方式会相对高效并行收集器
使用多线程的方式,利用多CUP来提高GC的效率
主要以到达一定的吞吐量为目标并发收集器
使用多线程的方式,利用多CUP来提高GC的效率
并发完成大部分工作,使得gc pause短试用场景单处理器机器且没有pause time的要求适用于科学技术和后台处理
有中规模/大规模数据集大小的应用且运行在多处理器上,关注吞吐量(throughput)适合中规模/大规模数据集大小的应用,应用服务器,电信领域
关注response time,而不是throughput使用Client模式下默认
可使用
可用-XX:+UseSerialGC强制使用
优点:对server应用没什么优点
缺点:慢,不能充分发挥硬件资源

Server模式下默认

--YGC:PS FGC:Parallel MSC

可用-XX:+UseParallelGC或-XX:+UseParallelOldGC强制指定

--ParallelGC代表FGC为Parallel MSC

--ParallelOldGC代表FGC为Parallel Compacting

优点:高效

缺点:当heap变大后,造成的暂停时间会变得比较长

可用-XX:+UseConcMarkSweepGC强制指定
优点:
对old进行回收时,对应用造成的暂停时间非常端,适合对latency要求比较高的应用
缺点:
1.内存碎片和浮动垃圾
2.old去的内存分配效率低
3.回收的整个耗时比较长
4.和应用争抢CPU内存回收触发YGC
eden空间不足
FGC
old空间不足
perm空间不足
显示调用System.gc() ,包括RMI等的定时触发
YGC时的悲观策略
dump live的内存信息时(jmap dump:live)YGC
eden空间不足
FGC
old空间不足
perm空间不足
显示调用System.gc() ,包括RMI等的定时触发
YGC时的悲观策略--YGC前&YGC后
dump live的内存信息时(jmap dump:live)YGC
eden空间不足
CMS GC
1.old Gen的使用率大的一定的比率 默认为92%
2.配置了CMSClassUnloadingEnabled,且Perm Gen的使用达到一定的比率 默认为92%
3.Hotspot自己根据估计决定是否要触法
4.在配置了ExplictGCInvokesConcurrent的情况下显示调用了System.gc.
Full GC(Serial MSC)
promotion failed 或 concurrent Mode Failure时;内存回收触发时发生了什么YGC
eden空间不足
FGC
old空间不足
perm空间不足
显示调用System.gc() ,包括RMI等的定时触发
YGC时的悲观策略
dump live的内存信息时(jmap dump:live)YGC
同serial动作基本相同,不同点:
1.多线程处理
2.YGC的最后不仅重新计算Tenuring Threshold,还会重新调整Eden和From的大小
FGC
1.如配置了ScavengeBeforeFullGC(默认),则先触发YGC(??)
2.MSC:清空heap中的no ref对象,permgen中已经被卸载的classloader中加载的class信息,并进行压缩
3.Compacting:清空heap中部分no ref的对象,permgen中已经被卸载的classloader中加载的class信息,并进行部分压缩
多线程做以上动作.YGC
同serial动作基本相同,不同点:
1.多线程处理
CMSGC:
1.old gen到达比率时只清除old gen中no ref的对象所占用的空间
2.perm gen到达比率时只清除已被清除的classloader加载的class信息
FGC
同serial细节参数可用-XX:+UseSerialGC强制使用
-XX:SurvivorRatio=x,控制eden/s0/s1的大小
-XX:MaxTenuringThreshold,用于控制对象在新生代存活的最大次数
-XX:PretenureSizeThreshold=x,控制超过多大的字节的对象就在old分配.-XX:SurvivorRatio=x,控制eden/s0/s1的大小
-XX:MaxTenuringThreshold,用于控制对象在新生代存活的最大次数

-XX:UseAdaptiveSizePolicy 去掉YGC后动态调整eden from已经tenuringthreshold的动作

-XX:ParallelGCThreads 设置并行的线程数

-XX:CMSInitiatingOccupancyFraction 设置old gen使用到达多少比率时触发
-XX:CMSInitiatingPermOccupancyFraction,设置Perm Gen使用到达多少比率时触发
-XX:+UseCMSInitiatingOccupancyOnly禁止hostspot自行触发CMS GC

?

?

注:

读书人网 >软件架构设计

热点推荐