JVM GC机制收集器与GC调优Word文档格式.docx
《JVM GC机制收集器与GC调优Word文档格式.docx》由会员分享,可在线阅读,更多相关《JVM GC机制收集器与GC调优Word文档格式.docx(20页珍藏版)》请在冰豆网上搜索。
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
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[<
collector>
:
<
startingoccupancy1>
->
endingoccupancy1>
<
pausetime1>
secs]<
startingoccupancy3>
endingoccupancy3>
pausetime3>
secs]
<
collector>
GC为minor收集过程中使用的垃圾收集器起的内部名称.
startingoccupancy1>
younggeneration在进行垃圾收集前被对象使用的存储空间.
endingoccupancy1>
younggeneration在进行垃圾收集后被对象使用的存储空间
minor收集使应用暂停的时间长短(秒)
startingoccupancy3>
整个堆(HeapSize)在进行垃圾收集前被对象使用的存储空间
整个堆(HeapSize)在进行垃圾收集后被对象使用的存储空间
整个垃圾收集使应用暂停的时间长短(秒),包括major收集使应用暂停的时间(如果发生了major收集).
GC信息的选项
-XX:
+PrintGCDetails显示GC的详细信息
+PrintGCApplicationConcurrentTime打印应用执行的时间
+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
+UseParallelGC或-XX:
+UseParallelOldGC强制指定
--ParallelGC代表FGC为ParallelMSC
--ParallelOldGC代表FGC为ParallelCompacting
高效
当heap变大后,造成的暂停时间会变得比较长
+UseConcMarkSweepGC强制指定
对old进行回收时,对应用造成的暂停时间非常端,适合对latency要求比较高的应用
1.内存碎片和浮动垃圾
2.old去的内存分配效率低
3.回收的整个耗时比较长
4.和应用争抢CPU
内存回收触发
显示调用System.gc(),包括RMI等的定时触发
YGC时的悲观策略--YGC前&
YGC后
CMSGC
1.oldGen的使用率大的一定的比率默认为92%
2.配置了CMSClassUnloadingEnabled,且PermGen的使用达到一定的比率默认为92%
3.Hotspot自己根据估计决定是否要触法
4.在配置了ExplictGCInvokesConcurrent的情况下显示调用了System.gc.
FullGC(SerialMSC)
promotionfailed或concurrentModeFailure时;
内存回收触发时发生了什么
同serial动作基本相同,不同点:
1.多线程处理
2.YGC的最后不仅重新计算TenuringThreshold,还会重新调整Eden和From的大小
1.如配置了ScavengeBeforeFullGC(默认),则先触发YGC(?
?
2.MSC:
清空heap中的noref对象,permgen中已经被卸载的classloader中加载的class信息,并进行压缩
3.Compacting:
清空heap中部分noref的对象,permgen中已经被卸载的classloader中加载的class信息,并进行部分压缩
多线程做以上动作.
CMSGC:
1.oldgen到达比率时只清除oldgen中noref的对象所占用的空间
2.permgen到达比率时只清除已被清除的classloader加载的class信息
同serial
细节参数
SurvivorRatio=x,控制eden/s0/s1的大小
MaxTenuringThreshold,用于控制对象在新生代存活的最大次数
PretenureSizeThreshold=x,控制超过多大的字节的对象就在old分配.
UseAdaptiveSizePolicy去掉YGC后动态调整edenfrom已经tenuringthreshold的动作
ParallelGCThreads设置并行的线程数
CMSInitiatingOccupancyFraction设置oldgen使用到达多少比率时触发
CMSInitiatingPermOccupancyFraction,设置PermGen使用到达多少比率时触发
+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=<
desirednumber>
来改变线程数。
还有两个参数-XX:
MaxGCPauseMillis=<
nnn>
和-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)(准备清理)
dotheremark;
resumeallapplicationthreads(第二次暂停,标记,检查)
*dotheconcurrentsweep(usesoneprocessorfortheconcurrentwork)(运行过程中清理)
*dotheconcurrentreset(usesoneprocessorfortheconcurrentwork)(复原)
当要使用Incrementalmode时,需要使用以下几个变量:
+CMSIncrementalModedefault:
disabled启动i-CMS模式(mustwith-XX:
+UseConcMarkSweepGC)
+CMSIncrementalPacingdefault:
disabled提供自动校正功能
CMSIncrementalDutyCycle=<
N>
default:
50启动CMS的上线
CMSIncrementalDutyCycleMin=<
10启动CMS的下线
CMSIncrementalSafetyFactor=<
10用来计算循环次数
CMSIncrementalOffset=<
0最小循环次数(Thisisthepercentage(0-100)bywhichtheincrementalmodedutycycleisshiftedtotherightwithintheperiodbetweenminorcollections.)
CMSExpAvgFactor=<
25提供一个指导收集数
SUN推荐的使用参数是:
+UseConcMarkSweepGC\
+CMSIncrementalMode\
+CMSIncrementalPacing\
CMSIncrementalDutyCycleMin=0\
CMSIncrementalDutyCycle=10\
+PrintGCDetails\
+PrintGCTimeStamps\
-TraceClassUnloading
如果使用throughputcollector和concurrentlowpausecollector,这两种垃圾收集器,需要适当的挺高内存大小,以为多线程做准备。
3.3、如何选择collector
∙app运行在单处理器机器上且没有pausetime的要求,让vm选择UseSerialGC.
∙重点考虑peakapplicationperformance(高性能),没有pausetime太严格要求,让vm选择或者UseParallelGC+UseParallelOldGC(optionally).
∙重