JVM调优方法论

 

新服务参数设置

新上线一个java服务,或者是RPC或者是WEB站点, 内存的设置该怎么设置呢?设置成多大比较合适,既不浪费内存,又不影响性能呢?

分析:
依据的原则是根据Java Performance里面的推荐公式来进行设置。

具体来讲:
Java整个堆大小设置,Xmx 和 Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍
永久代 PermSize和MaxPermSize设置为老年代存活对象的1.2-1.5倍。
年轻代Xmn的设置为老年代存活对象的1-1.5倍。
老年代的内存大小设置为老年代存活对象的2-3倍。

BTW:
     1、Sun官方建议年轻代的大小为整个堆的3/8左右, 所以按照上述设置的方式,基本符合Sun的建议。 
     2、堆大小=年轻代大小+年老代大小, 即xmx=xmn+老年代大小 。 Permsize不影响堆大小。
     3、为什么要按照上面的来进行设置呢? 没有具体的说明,但应该是根据多种调优之后得出的一个结论。

如何确认老年代存活对象大小?
     JVM参数中添加GC日志,GC日志中会记录每次FullGC之后各代的内存大小,观察老年代GC之后的空间大小。可观察一段时间内(比如2天)的FullGC之后的内存情况,根据多次的FullGC之后的老年代的空间大小数据来预估FullGC之后老年代的存活对象大小(可根据多次FullGC之后的内存大小取平均值)

老服务调优

对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数

1.监控GC的状态

使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执行时间,觉得是否进行优化。

举一个例子: 系统崩溃前的一些现象:

  • 每次垃圾回收的时间越来越长,由之前的10ms延长到50ms左右,FullGC的时间也有之前的0.5s延长到4、5s
  • FullGC的次数越来越多,最频繁时隔不到1分钟就进行一次FullGC
  • 年老代的内存越来越大并且每次FullGC后年老代没有内存被释放

之后系统会无法响应新的请求,逐渐到达OutOfMemoryError的临界值,这个时候就需要分析JVM内存快照dump。

2.生成堆的dump文件

通过JMX的MBean生成当前的Heap信息,大小为一个3G(整个堆的大小)的hprof文件,如果没有启动JMX可以通过Java的jmap命令来生成该文件。

3.分析dump文件

打开这个3G的堆信息文件,显然一般的Window系统没有这么大的内存,必须借助高配置的Linux,几种工具打开该文件:

  • Visual VM
  • IBM HeapAnalyzer
  • JDK 自带的Hprof工具
  • Mat(Eclipse专门的静态内存分析工具)推荐使用

备注:文件太大,建议使用Eclipse专门的静态内存分析工具Mat打开分析。

4.分析结果,判断是否需要优化

如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化,如果GC时间超过1-3秒,或者频繁GC,则必须优化。

注:如果满足下面的指标,则一般不需要进行GC:

  • Minor GC执行时间不到50ms;
  • Minor GC执行不频繁,约10秒一次;
  • Full GC执行时间不到1s;
  • Full GC执行频率不算频繁,不低于10分钟1次;

5.调整GC类型和内存分配

如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择。

6.不断的分析和调整

通过不断的试验和试错,分析并找到最合适的参数,如果找到了最合适的参数,则将这些参数应用到所有服务器。

JVM调优方法论_第1张图片

JVM调优参数参考

1.针对JVM堆的设置,一般可以通过-Xms -Xmx限定其最小、最大值,为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,通常把最大、最小设置为相同的值;

2.年轻代和年老代将根据默认的比例(1:2)分配堆内存, 可以通过调整二者之间的比率NewRadio来调整二者之间的大小,也可以针对回收代。

比如年轻代,通过 -XX:newSize -XX:MaxNewSize来设置其绝对大小。同样,为了防止年轻代的堆收缩,我们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小。

3.年轻代和年老代设置多大才算合理

1)更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC

2)更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率

如何选择应该依赖应用程序对象生命周期的分布情况: 如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性。

在抉择时应该根 据以下两点:

(1)本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理 。

(2)通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间。

4.在配置较好的机器上(比如多核、大内存),可以为年老代选择并行收集算法: -XX:+UseParallelOldGC 

5.线程堆栈的设置:每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般256K就足用。

理论上,在内存不变的情况下,减少每个线程的堆栈,可以产生更多的线程,但这实际上还受限于操作系统。

JVM常见参数

配置垃圾回收器参数

-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器,更加关注吞吐量
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:设置用于垃圾回收的线程数
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:设定CMS的线程数量
-XX:+UseG1GC:启用G1垃圾回收器

CMS常见参数

-Xms2560m

堆初始大小为2560M

-Xmx2560m

堆最大为2560M

-Xss512k

每个线程堆栈大小为512K

-XX:PermSize=128m

持久代(perm gen)初始大小为128M

-XX:MaxPermSize=384m

持久代最大为384M

-XX:NewSize=1536m

新生代初始大小为1536M

-XX:MaxNewSize=1536m

新生代最大为1536M

-XX:SurvivorRatio=22

新生代Eden区与Survivor区的比值,因为新生代大小为1536,Eden区大小为1536*22/(22+2)=1408,每个Survivor区为64M

-XX:+UseParNewGC

新生代垃圾收集器为ParNew,可与CMS同时使用

-XX:ParallelGCThreads=4

并行收集的线程数为4

-XX:MaxTenuringThreshold=9

对象晋升老年代的年龄阈值为9

-XX:+UseConcMarkSweepGC

老年代使用CMS垃圾收集器

-XX:+DisableExplicitGC

禁用System.gc()

-XX:+UseCMSInitiatingOccupancyOnly

指定HotSpot VM总是使用-XX:CMSInitiatingOccupancyFraction的值作为老年代使用率限制来启动CMS垃圾回收。如果没有使用-XX:+UseCMSInitiatingOccupancyOnly,那么HotSpot VM只是利用CMSInitiatingOccupancyFraction启动第一次CMS垃圾回收,后面都是使用HotSpot VM自动计算出来的值

-XX:+ScavengeBeforeFullGC

在Full GC前触发一次Minor GC

-XX:+UseCMSCompactAtFullCollection

FULL GC时对老年代进行压缩。CMS默认不会移动内存,因此容易产生碎片。增加该参数虽然会影响性能,但可以消除碎片

-XX:+CMSParallelRemarkEnabled

开启并行标记,减少停顿时间

-XX:CMSFullGCsBeforeCompaction=9

9次以后进行内存压缩。由于并发收集器不对内存空间进行压缩整理,所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩整理

-XX:CMSInitiatingOccupancyFraction=60

老年代使用率达到60%时,触发GC回收

-XX:+CMSClassUnloadingEnabled

垃圾回收会清理持久代,移除不再使用的classes。这个参数只有在UseConcMarkSweepGC也启用的情况下才有用

-XX:SoftRefLRUPolicyMSPerMB=0

每MB堆中软引用(soft reference)对象的存活时间。软引用用于描述一些有用但并非必须的对象。对于软引用关联的对象,在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围内进行二次回收。如果这次回收还没有足够内存,才会抛出内存溢出异常

-XX:-ReduceInitialCardMarks

为解决jdk 6u18 放入大对象导致jvm crash的一个配置参数

-XX:+CMSPermGenSweepingEnabled

允许对持久代进行清理

-XX:CMSInitiatingPermOccupancyFraction=70

持久代使用率超过70%触发GC

-XX:+ExplicitGCInvokesConcurrent

命令JVM无论什么时候调用系统GC,都执行CMS GC,而不是Full GC (一个case)

-XX:+PrintGCDetails

打印GC详情

-XX:+PrintGCTimeStamps

打印以JVM启动时间为基准的相对时间

-XX:+PrintGCApplicationConcurrentTime

打印每次垃圾回收前,程序未中断的执行时间

-XX:+PrintHeapAtGC

打印GC前后的详细堆栈信息

-Xloggc:/data/applogs/heap_trace.txt

日志信息地址

-XX:-HeapDumpOnOutOfMemoryError

在java.lang.OutOfMemoryError异常出现时,输出一个dump.core文件,记录当时的堆内存快照

-XX:HeapDumpPath=/data/applogs/HeapDumpOnOutOfMemoryError

堆内存快照地址

 

你可能感兴趣的:(jvm)