JVM GC机制收集器与GC调优.docx
《JVM GC机制收集器与GC调优.docx》由会员分享,可在线阅读,更多相关《JVM GC机制收集器与GC调优.docx(20页珍藏版)》请在冰豆网上搜索。
JVMGC机制收集器与GC调优
JVMGC机制、收集器与GC调优
一、回顾JVM内存分配
1.1、内存分配:
1、对象优先在EDEN分配
2、大对象直接进入老年代
3、长期存活的对象将进入老年代
4、适龄对象也可能进入老年代:
动态对象年龄判断
动态对象年龄判断:
虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,当Survivor空间的相同年龄的所有对象大小总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中指定的年龄
1.2、总结一下:
1、对象优先在Eden分配,这里大部分对象具有朝生夕灭的特征,MinorGC主要清理该处
2、大对象(占内存大)、老对象(使用频繁)
3、Survivor无法容纳的对象,将进入老年代,FullGC的主要清理该处
二、JVM的GC机制
JVM有2个GC线程
第一个线程负责回收Heap的Young区
第二个线程在Heap不足时,遍历Heap,将Young区升级为Older区
Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能。
2.1、堆内存GC
JVM(采用分代回收的策略),用较高的频率对年轻的对象(younggeneration)进行YGC,而对老对象(tenured generation)较少(tenured generation满了后才进行)进行FullGC。
这样就不需要每次GC都将内存中所有对象都检查一遍。
2.2、非堆内存不GC
GC不会在主程序运行期对PermGenSpace进行清理,所以如果你的应用中有很多CLASS(特别是动态生成类,当然permgenspace存放的内容不仅限于类)的话,就很可能出现PermGenSpace错误。
2.3、内存申请、对象衰老过程
2.3.1、内存申请过程
1.JVM会试图为相关Java对象在Eden中初始化一块内存区域;
2.当Eden空间足够时,内存申请结束。
否则到下一步;
3.JVM试图释放在Eden中所有不活跃的对象(minorcollection),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
4.Survivor区被用来作为Eden及old的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区;
5.当old区空间不够时,JVM会在old区进行majorcollection;
6.完全垃圾收集后,若Survivor及old区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现"Outofmemory错误";
2.3.2、对象衰老过程
1.新创建的对象的内存都分配自eden。
Minorcollection的过程就是将eden和在用survivorspace中的活对象copy到空闲survivorspace中。
对象在younggeneration里经历了一定次数(可以通过参数配置)的minorcollection后,就会被移到oldgeneration中,称为tenuring。
GC触发条件
GC类型
触发条件
触发时发生了什么
注意
查看方式
YGC
eden空间不足
清空Eden+fromsurvivor中所有noref的对象占用的内存
将eden+fromsur中所有存活的对象copy到tosur中
一些对象将晋升到old中:
tosur放不下的
存活次数超过turningthreshold中的
重新计算tenuringthreshold(serialparallelGC会触发此项)
重新调整Eden和from的大小(parallelGC会触发此项)
全过程暂停应用
是否为多线程处理由具体的GC决定
jstat–gcutil
gclog
FGC
old空间不足
perm空间不足
显示调用System.GC,RMI等的定时触发
YGC时的悲观策略
dumplive的内存信息时(jmap–dump:
live)
清空heap中noref的对象
permgen中已经被卸载的classloader中加载的class信息
如配置了CollectGenOFirst,则先触发YGC(针对serialGC)
如配置了ScavengeBeforeFullGC,则先触发YGC(针对serialGC)
全过程暂停应用
是否为多线程处理由具体的GC决定
是否压缩需要看配置的具体GC
jstat–gcutil
gclog
permanentgeneration空间不足会引发FullGC,仍然不够会引发PermGenSpace错误。
三、GC监视、收集器与GC调优
3.1、监视JVMGC
首先说一下如何监视JVMGC,可以用JDK中的jstat工具,也可以在java程序启动的opt里加上如下几个参数(注:
这两个参数只针对SUN的HotSpotVM):
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]
他们分别显示了JVMGC的过程,清理出了多少空间。
第一行GC使用的是‘普通GC’(MinorCollections),第二行使用的是‘全GC’(MajorCollections)。
他们的区别很大,在第一行最后我们可以看见他的时间是0.0233874秒,而第二行的FullGC的时间是0.2371537秒。
第二行的时间是第一行的接近10倍,也就是我们这次调优的重点,减少FullGC的次数,以为FullGC会暂停程序比较长的时间,如果FullGC的次数比较多。
程序就会经常性的假死。
注:
GC信息的格式
[GC[:
->,secs]->,secs]
GC为minor收集过程中使用的垃圾收集器起的内部名称.
younggeneration在进行垃圾收集前被对象使用的存储空间.
younggeneration在进行垃圾收集后被对象使用的存储空间
minor收集使应用暂停的时间长短(秒)
整个堆(HeapSize)在进行垃圾收集前被对象使用的存储空间
整个堆(HeapSize)在进行垃圾收集后被对象使用的存储空间
整个垃圾收集使应用暂停的时间长短(秒),包括major收集使应用暂停的时间(如果发生了major收集).
GC信息的选项
-XX:
+PrintGCDetails显示GC的详细信息
-XX:
+PrintGCApplicationConcurrentTime打印应用执行的时间
-XX:
+PrintGCApplicationStoppedTime打印应用被暂停的时间
3.2、collector收集器的种类
GC在HotSpotVM5.0里有四种:
incremental(sometimescalledtrain)lowpausecollector已被废弃,不在介绍.
类别
serialcollector
parallelcollector
( throughputcollector )
concurrentcollector
(concurrentlowpausecollector)
介绍
单线程收集器
使用单线程去完成所有的gc工作,没有线程间的通信,这种方式会相对高效
并行收集器
使用多线程的方式,利用多CUP来提高GC的效率
主要以到达一定的吞吐量为目标
并发收集器
使用多线程的方式,利用多CUP来提高GC的效率
并发完成大部分工作,使得gcpause短
试用场景
单处理器机器且没有pausetime的要求
适用于科学技术和后台处理
有中规模/大规模数据集大小的应用且运行在多处理器上,关注吞吐量(throughput)
适合中规模/大规模数据集大小的应用,应用服务器,电信领域
关注responsetime,而不是throughput
使用
Client模式下默认
可使用
可用-XX:
+UseSerialGC强制使用
优点:
对server应用没什么优点
缺点:
慢,不能充分发挥硬件资源
Server模式下默认
--YGC:
PSFGC:
ParallelMSC
可用-XX:
+UseParallelGC或-XX:
+UseParallelOldGC强制指定
--ParallelGC代表FGC为ParallelMSC
--ParallelOldGC代表FGC为ParallelCompacting
优点:
高效
缺点:
当heap变大后,造成的暂停时间会变得比较长
可用-XX:
+UseConcMarkSweepGC强制指定
优点:
对old进行回收时,对应用造成的暂停时间非常端,适合对latency要求比较高的应用
缺点:
1.内存碎片和浮动垃圾
2.old去的内存分配效率低
3.回收的整个耗时比较长
4.和应用争抢CPU
内存回收触发
YGC
eden空间不足
FGC
old空间不足
perm空间不足
显示调用System.gc(),包括RMI等的定时触发
YGC时的悲观策略
dumplive的内存信息时(jmap–dump:
live)
YGC
eden空间不足
FGC
old空间不足
perm空间不足
显示调用System.gc(),包括RMI等的定时触发
YGC时的悲观策略--YGC前&YGC后
dumplive的内存信息时(jmap–dump:
live)
YGC
eden空间不足
CMSGC
1.oldGen的使用率大的一定的比率默认为92%
2.配置了CMSClassUnloadingEnabled,且PermGen的使用达到一定的比率默认为92%
3.Hotspot自己根据估计决定是否要触法
4.在配置了ExplictGCInvokesConcurrent的情况下显示调用了System.gc.
FullGC(SerialMSC)
promotionfailed或concurrentModeFailure时;
内存回收触发时发生了什么
YGC
eden空间不足
FGC
old空间不足
perm空间不足
显示调用System.gc(),包括RMI等的定时触发
YGC时的悲观策略
dumplive的内存信息时(jmap–dump:
live)
YGC
同serial动作基本相同,不同点:
1.多线程处理
2.YGC的最后不仅重新计算TenuringThreshold,还会重新调整Eden和From的大小
FGC
1.如配置了ScavengeBeforeFullGC(默认),则先触发YGC(?
?
)
2.MSC:
清空heap中的noref对象,permgen中已经被卸载的classloader中加载的class信息,并进行压缩
3.Compacting:
清空heap中部分noref的对象,permgen中已经被卸载的classloader中加载的class信息,并进行部分压缩
多线程做以上动作.
YGC
同serial动作基本相同,不同点:
1.多线程处理
CMSGC:
1.oldgen到达比率时只清除oldgen中noref的对象所占用的空间
2.permgen到达比率时只清除已被清除的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后动态调整edenfrom已经tenuringthreshold的动作
-XX:
ParallelGCThreads设置并行的线程数
-XX:
CMSInitiatingOccupancyFraction设置oldgen使用到达多少比率时触发
-XX:
CMSInitiatingPermOccupancyFraction,设置PermGen使用到达多少比率时触发
-XX:
+UseCMSInitiatingOccupancyOnly禁止hostspot自行触发CMSGC
注:
∙throughputcollector与concurrentlowpausecollector的区别是throughputcollector只在youngarea使用使用多线程,而concurrentlowpausecollector则在tenuredgeneration也使用多线程。
∙根据官方文档,他们俩个需要在多CPU的情况下,才能发挥作用。
在一个CPU的情况下,会不如默认的serialcollector,因为线程管理需要耗费CPU资源。
而在两个CPU的情况下,也提高不大。
只是在更多CPU的情况下,才会有所提高。
当然concurrentlowpausecollector有一种模式可以在CPU较少的机器上,提供尽可能少的停顿的模式,见CMSGCIncrementalmode。
∙当要使用throughputcollector时,在javaopt里加上-XX:
+UseParallelGC,启动throughputcollector收集。
也可加上-XX:
ParallelGCThreads=来改变线程数。
还有两个参数-XX:
MaxGCPauseMillis=和-XX:
GCTimeRatio=,MaxGCPauseMillis=用来控制最大暂停时间,而-XX:
GCTimeRatio可以提高GC说占CPU的比,以最大话的减小heap。
附注SUN的官方说明:
1.Thethroughputcollector:
thiscollectorusesaparallelversionoftheyounggenerationcollector.Itisusedifthe-XX:
+UseParallelGCoptionispassedonthecommandline.Thetenuredgenerationcollectoristhesameastheserialcollector.
2.Theconcurrentlowpausecollector:
thiscollectorisusedifthe-Xincgc™or-XX:
+UseConcMarkSweepGCispassedonthecommandline.Theconcurrentcollectorisusedtocollectthetenuredgenerationanddoesmostofthecollectionconcurrentlywiththeexecutionoftheapplication.Theapplicationispausedforshortperiodsduringthecollection.Aparallelversionoftheyounggenerationcopyingcollectorisusedwiththeconcurrentcollector.Theconcurrentlowpausecollectorisusediftheoption-XX:
+UseConcMarkSweepGCispassedonthecommandline.
3.Theincremental(sometimescalledtrain)lowpausecollector:
thiscollectorisusedonlyif-XX:
+UseTrainGCispassedonthecommandline.ThiscollectorhasnotchangedsincetheJ2SEPlatformversion1.4.2andiscurrentlynotunderactivedevelopment.Itwillnotbesupportedinfuturereleases.Pleaseseethe1.4.2GCTuningDocumentforinformationonthiscollector.
CMSGCIncrementalmode
当要使用concurrentlowpausecollector时,在java的opt里加上-XX:
+UseConcMarkSweepGC。
concurrentlowpausecollector还有一种为CPU少的机器准备的模式,叫Incrementalmode。
这种模式使用一个CPU来在程序运行的过程中GC,只用很少的时间暂停程序,检查对象存活。
在Incrementalmode里,每个收集过程中,会暂停两次,第二次略长。
第一次用来,简单从root查询存活对象。
第二次用来,详细检查存活对象。
整个过程如下:
*stopallapplicationthreads;dotheinitialmark;resumeallapplicationthreads(第一次暂停,初始话标记)
*dotheconcurrentmark(usesoneprocesorfortheconcurrentwork)(运行是标记)
*dotheconcurrentpre-clean(usesoneprocessorfortheconcurrentwork)(准备清理)
*stopallapplicationthreads;dotheremark;resumeallapplicationthreads(第二次暂停,标记,检查)
*dotheconcurrentsweep(usesoneprocessorfortheconcurrentwork)(运行过程中清理)
*dotheconcurrentreset(usesoneprocessorfortheconcurrentwork)(复原)
当要使用Incrementalmode时,需要使用以下几个变量:
-XX:
+CMSIncrementalModedefault:
disabled启动i-CMS模式(mustwith-XX:
+UseConcMarkSweepGC)
-XX:
+CMSIncrementalPacingdefault:
disabled提供自动校正功能
-XX:
CMSIncrementalDutyCycle=default:
50启动CMS的上线
-XX:
CMSIncrementalDutyCycleMin=default:
10启动CMS的下线
-XX:
CMSIncrementalSafetyFactor=default:
10用来计算循环次数
-XX:
CMSIncrementalOffset=default:
0最小循环次数(Thisisthepercentage(0-100)bywhichtheincrementalmodedutycycleisshiftedtotherightwithintheperiodbetweenminorcollections.)
-XX:
CMSExpAvgFactor=default:
25提供一个指导收集数
SUN推荐的使用参数是:
-XX:
+UseConcMarkSweepGC\
-XX:
+CMSIncrementalMode\
-XX:
+CMSIncrementalPacing\
-XX:
CMSIncrementalDutyCycleMin=0\
-XX:
CMSIncrementalDutyCycle=10\
-XX:
+PrintGCDetails\
-XX:
+PrintGCTimeStamps\
-XX:
-TraceClassUnloading
注:
如果使用throughputcollector和concurrentlowpausecollector,这两种垃圾收集器,需要适当的挺高内存大小,以为多线程做准备。
3.3、如何选择collector
∙app运行在单处理器机器上且没有pausetime的要求,让vm选择UseSerialGC.
∙重点考虑peakapplicationperformance(高性能),没有pausetime太严格要求,让vm选择或者UseParallelGC+UseParallelOldGC(optionally).
∙重