JVM调优

1.Heap设定与垃圾回收

JavaHeap分为3个区,Young,Old和Permanent。Young保存刚实例化的对象。当该区被填满时,GC会将对象移到Old区。Permanent区则负责保存反射对象,本文不讨论该区。

JVM的Heap分配可以使用-X参数设定,

-Xms初始Heap大小

-Xmxjavaheap最大值

-Xmnyounggeneration的heap大小

JVM 有2个GC线程。第一个线程负责回收Heap的Young区。第二个线程在Heap不足时,遍历Heap,将Young区升级为Older区。 Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能。

为什么一些程序频繁发生GC?有如下原因:

1)程序内调用了System.gc()或Runtime.gc()。

2)一些中间件软件调用自己的GC方法,此时需要设置参数禁止这些GC。

3)Java的Heap太小,一般默认的Heap值都很小。

4)频繁实例化对象,Release对象。此时尽量保存并重用对象,例如使用StringBuffer()和String()。

如果你发现每次GC后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态。许多Server端的Java程序每次GC后最好能有65%的剩余空间。

经验之谈:

1)Server端JVM最好将-Xms和-Xmx设为相同值。为了优化GC,最好让-Xmn值约等于-Xmx的1/3[2]。

2)一个GUI程序最好是每10到20秒间运行一次GC,每次在半秒之内完成[2]。


注意:

1)增加Heap的大小虽然会降低GC的频率,但也增加了每次GC的时间。并且GC运行时,所有的用户线程将暂停,也就是GC期间,Java应用程序不做任何工作。

2)Heap大小并不决定进程的内存使用量。进程的内存使用量要大于-Xmx定义的值,因为Java为其他任务分配内存,例如每个线程的Stack等。


2.Stack的设定

每个线程都有他自己的Stack。

-Xss每个线程的Stack大小

Stack的大小限制着线程的数量。如果Stack过大就好导致内存溢漏。-Xss参数决定Stack大小,例如-Xss1024K。如果Stack太小,也会导致Stack溢漏。

3.硬件环境

硬件环境也影响GC的效率,例如机器的种类,内存,swap空间,和CPU的数量。

如果你的程序需要频繁创建很多transient对象,会导致JVM频繁GC。这种情况你可以增加机器的内存,来减少Swap空间的使用[2]。

4.4种GC

第一种为单线程GC,也是默认的GC。,该GC适用于单CPU机器。

第二种为ThroughputGC,是多线程的GC,适用于多CPU,使用大量线程的程序。第二种GC与第一种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程。-XX:+UseParallelGC参数启动该GC。

第三种为ConcurrentLowPauseGC,类似于第一种,适用于多CPU,并要求缩短因GC造成程序停滞的时间。这种GC可以在Old区的回收同时,运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC。

第四种为IncrementalLowPauseGC,适用于要求缩短因GC造成程序停滞的时间。这种GC可以在Young区回收的同时,回收一部分Old区对象。-Xincgc参数启动该GC。


最后附上用java-X命令查看JVM的配置说明:

D:/j2sdk15/bin>java-X

-Xmixedmixedmodeexecution(default)

-Xintinterpretedmodeexecutiononly

-Xbootclasspath:<directoriesandzip/jarfilesseparatedby;>

setsearchpathforbootstrapclassesandresources

-Xbootclasspath/a:<directoriesandzip/jarfilesseparatedby;>

appendtoendofbootstrapclasspath

-Xbootclasspath/p:<directoriesandzip/jarfilesseparatedby;>

prependinfrontofbootstrapclasspath

-Xnoclassgcdisableclassgarbagecollection

-Xincgcenableincrementalgarbagecollection

-Xloggc:<file>logGCstatustoafilewithtimestamps

-Xbatchdisablebackgroundcompilation

-Xms<size>setinitialJavaheapsize

-Xmx<size>setmaximumJavaheapsize

-Xss<size>setjavathreadstacksize

-Xprofoutputcpuprofilingdata

-Xfutureenablestrictestchecks,anticipatingfuturedefault

-XrsreduceuseofOSsignalsbyJava/VM(seedocumentation)

-Xcheck:jniperformadditionalchecksforJNIfunctions

-Xshare:offdonotattempttousesharedclassdata

-Xshare:autousesharedclassdataifpossible(default)

-Xshare:onrequireusingsharedclassdata,otherwisefail.



The-Xoptionsarenon-standardandsubjecttochangewithoutnotice.

-----------------------------------------------------------------------



JVM配置参数中文说明:

-----------------------------------------------------------------------

1、-Xmixedmixedmodeexecution(default)

混合模式执行

2、-Xintinterpretedmodeexecutiononly

解释模式执行

3、-Xbootclasspath:<directoriesandzip/jarfilesseparatedby;>

setsearchpathforbootstrapclassesandresources

设置zip/jar资源或者类(.class文件)存放目录路径

3、-Xbootclasspath/a:<directoriesandzip/jarfilesseparatedby;>

appendtoendofbootstrapclasspath

追加zip/jar资源或者类(.class文件)存放目录路径

4、-Xbootclasspath/p:<directoriesandzip/jarfilesseparatedby;>

prependinfrontofbootstrapclasspath

预先加载zip/jar资源或者类(.class文件)存放目录路径

5、-Xnoclassgcdisableclassgarbagecollection

关闭类垃圾回收功能

6、-Xincgcenableincrementalgarbagecollection

开启类的垃圾回收功能

7、-Xloggc:<file>logGCstatustoafilewithtimestamps

记录垃圾回日志到一个文件。

8、-Xbatchdisablebackgroundcompilation

关闭后台编译

9、-Xms<size>setinitialJavaheapsize

设置JVM初始化堆内存大小

10、-Xmx<size>setmaximumJavaheapsize

设置JVM最大的堆内存大小

11、-Xss<size>setjavathreadstacksize

设置JVM栈内存大小

12、-Xprofoutputcpuprofilingdata

输入CPU概要表数据

13、-Xfutureenablestrictestchecks,anticipatingfuturedefault

执行严格的代码检查,预测可能出现的情况

14、-XrsreduceuseofOSsignalsbyJava/VM(seedocumentation)

通过JVM还原操作系统信号

15、-Xcheck:jniperformadditionalchecksforJNIfunctions

对JNI函数执行检查

16、-Xshare:offdonotattempttousesharedclassdata

尽可能不去使用共享类的数据

17、-Xshare:autousesharedclassdataifpossible(default)

尽可能的使用共享类的数据

18、-Xshare:onrequireusingsharedclassdata,otherwisefail.

尽可能的使用共享类的数据,否则运行失败


The-Xoptionsarenon-standardandsubjecttochangewithoutnotice.

调整JVMGC(GarbageCollection),可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率。但是调整GC是以个极为复杂的过程,

由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要cup个数,内存不同),

所以使用的GC种类也会不同。接下来,我简单介绍一下如何调整GC。

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

-XX:-PrintGCPrintmessagesatgarbagecollection.Manageable.

-XX:-PrintGCDetailsPrintmoredetailsatgarbagecollection.Manageable.(Introducedin1.4.0.)

-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]



他们分别显示了GC的过程,清理出了多少空间。第一行GC使用的是‘普通GC’(MinorCollections),第二行使用的是‘全GC’(MajorCollections)。他们的区别很大,在第一行最后

我们可以看见他的时间是0.0233874秒,而第二行的FullGC的时间是0.2371537秒。第二行的时间是第一行的接近10倍,也就是我们这次调优的重点,减少FullGC的次数,因为FullGC

会暂停程序比较长的时间,如果FullGC的次数比较多。程序就会经常性的假死。当然这只是他们的表面现象,接下来我仔细介绍一下GC,和FullGC(为后面的调优做准备)。



我们知道Java和C++的区别主要是,Java不需要像c++那样,由程序员主动的释放内存。而是由JVM里的GC(GarbageCollection)来,在适当的时候替我们释放内存。GC的内部工作,

即GC的算法有很多种,如:标记清除收集器,压缩收集器,分代收集器等等。现在比较常用的是分代收集(也是SUNVM使用的),即将内存分为几个区域,将不同生命周期的对象放在不同区域里

(新的对象会先生成在Youngarea,在几次GC以后,如过没有收集到,就会逐渐升级到Tenuredarea)。在GC收集的时候,频繁收集生命周期短的区域(Youngarea),因为这个区域内的

对象生命周期比较短,GC效率也会比较高。而比较少的收集生命周期比较长的区域(OldareaorTenuredarea),以及基本不收集的永久区(Permarea)。



注:Youngarea又分为三个区域分别叫Eden,和俩个Survivorspaces。Eden用来存放新的对象,Survivorspaces用于新对象升级到Tenuredarea时的拷贝。

我们管收集生命周期短的区域(Youngarea)的收集叫GC,而管收集生命周期比较长的区域(OldareaorTenuredarea)的收集叫FullGC,因为他们的收集算法不同,

所以使用的时间也会不同。我们要尽量减少FullGC的次数。



接下来介绍一下HotSpotVMGC的种类,GC在HotSpotVM5.0里有四种。一种是默认的叫serialcollector,另外几种分别叫throughputcollector,concurrent

lowpausecollector,incremental(sometimescalledtrain)lowpausecollector(废弃掉了)。以下是SUN的官方说明:



1.Thethroughputcollector:thiscollectorusesaparallelversionoftheyounggenerationcollector.Itisusedifthe

-XX:+UseParallelGCoptionispassedonthecommandline.Thetenuredgenerationcollectoristhesameastheserialcollector.

2.Theconcurrentlowpausecollector:thiscollectorisusedifthe-Xincgc&#8482;or-XX:+UseConcMarkSweepGCispassedonthecommandline.

Theconcurrentcollectorisusedtocollectthetenuredgenerationanddoesmostofthecollectionconcurrentlywiththeexecutionof

theapplication.Theapplicationispausedforshortperiodsduringthecollection.Aparallelversionoftheyounggenerationcopying

collectorisusedwiththeconcurrentcollector.Theconcurrentlowpausecollectorisusediftheoption-XX:+UseConcMarkSweepGCis

passedonthecommandline.

3.Theincremental(sometimescalledtrain)lowpausecollector:thiscollectorisusedonlyif-XX:+UseTrainGCispassedonthe

commandline.ThiscollectorhasnotchangedsincetheJ2SEPlatformversion1.4.2andiscurrentlynotunderactivedevelopment.

Itwillnotbesupportedinfuturereleases.Pleaseseethe1.4.2GCTuningDocumentforinformationonthiscollector.



简单来说就是throughputcollector和concurrentlowpausecollector:使用多线程的方式,利用多CUP来提高GC的效率,而throughputcollector与concurrent

lowpausecollector的去别是throughputcollector只在youngarea使用使用多线程,而concurrentlowpausecollector则在tenuredgeneration也使用多线程。



根据官方文档,他们俩个需要在多CPU的情况下,才能发挥作用。在一个CPU的情况下,会不如默认的serialcollector,因为线程管理需要耗费CPU资源。而在两个CPU的情况下,

也挺高不大。只是在更多CPU的情况下,才会有所提高。当然concurrentlowpausecollector有一种模式可以在CPU较少的机器上,提供尽可能少的停顿的模式,见下文。



当要使用throughputcollector时,在javaopt里加上-XX:+UseParallelGC,启动 throughputcollector收集。也可加上-XX:ParallelGCThreads=<desirednumber>来改变线程数。

还有两个参数-XX:MaxGCPauseMillis=<nnn>和-XX:GCTimeRatio=& lt;nnn>,MaxGCPauseMillis=<nnn>用来控制最大暂停时间,而-XX:GCTimeRatio可以提高 GC说占CPU的比,

以最大话的减小heap。



当要使用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=<N>default:50启动CMS的上线

-XX:CMSIncrementalDutyCycleMin=<N>default:10启动CMS的下线

-XX:CMSIncrementalSafetyFactor=<N>default:10用来计算循环次数

-XX:CMSIncrementalOffset=<N>default:0最小循环次数(Thisisthepercentage(0-



100)bywhichtheincrementalmodedutycycleisshiftedtotherightwithintheperiod



betweenminorcollections.)

-XX:CMSExpAvgFactor=<N>default:25提供一个指导收集数



SUN推荐的使用参数是:



-XX:+UseConcMarkSweepGC/

-XX:+CMSIncrementalMode/

-XX:+CMSIncrementalPacing/

-XX:CMSIncrementalDutyCycleMin=0/

-XX:CMSIncrementalDutyCycle=10/

-XX:+PrintGCDetails/

-XX:+PrintGCTimeStamps/

-XX:-TraceClassUnloading

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值