高手的存在,就是让服务10亿人的时候,你感觉只是为你一个人服务......

JVM 配置参数整理

目录
  1. 1. -XX:+PrintFlagsFinal
  2. 2. 查看jvm运行参数
  3. 3. 常用参数说明
    1. 3.1. 全局参数
      1. 3.1.1. -Xms -Xmx
      2. 3.1.2. -XX:+DisableExplicitGC与-XX+ExplicitGCInvokesConcurrent
      3. 3.1.3. -XX:+UseAdaptiveSizePolicy
      4. 3.1.4. -XX:ConcGCThreads
      5. 3.1.5. -XX:CMSInitiatingOccupancyFraction
      6. 3.1.6. -XX:-ScavengeBeforeFullGC
    2. 3.2. 监控参数
      1. 3.2.1. -XX:HeapDumpPath
      2. 3.2.2. -verbose:gc与-XX:+PrintGC
  4. 4. 参考:

-XX:+PrintFlagsFinal

当你在网上兴冲冲找到一个可优化的参数时,先用-XX: +PrintFlagsFinal看看,它可能已经默认打开了;不要轻信网上任何文章,一切以JDK打出来的为准
-XX:+PrintFlagsFinal显示所有可设置的参数及它们的值( JDK 6 update 21开始才可以用),默认是不包括diagnostic或experimental系的。
要在-XX:+PrintFlagsFinal的输出里看到这两种参数的信息,分别需要显式指定

-XX:+UnlockDiagnosticVMOptions
-XX:+UnlockExperimentalVMOptions

另外,可以先看一下R大的JVM调优的”标准参数”的各种陷阱这篇文章。

查看jvm运行参数

jinfo -flags pid

在JDK 7开始可以使用jcmd
jcmd pidVM.flags

常用参数说明

把参数分为全局参数,监控参数,eden区参数,survivor区参数,old区参数,perm区参数

全局参数

-Xms -Xmx

-Xms 初始化堆大小,-Xmx 最大堆大小。默认空余堆内存小于40%,自动扩展到-Xmx的值。
-Xms和-Xmx一般情况设置相同的值,避免扩展内存带来的损耗。

单机部署server的情况下,-Xmx的设置建议在物理内存的1/2到2/3之间。
Java进程消耗的总内存肯定大于最大堆内存:

java总内存=堆内存(Xmx)+ 方法区内存(MaxPermSize)+ 栈内存(Xss,包括虚拟机栈和本地方法栈)*线程数 + direct memory + JNI代码 + 虚拟机和GC本身内存开销

留更多的内存提升系统容错性。


-XX:+DisableExplicitGC与-XX+ExplicitGCInvokesConcurrent

-XX:+DisableExplicitGC:
用来禁止system.gc对gc的触发,加上后system.gc()将不会触发gc。
System.gc()的默认效果是引发一次stop-the-world的full GC,对整个GC堆做收集。

为啥要用这个参数呢?
最主要的原因是为了防止某些手贱的同学在代码里到处写System.gc()的调用而干扰了程序的正常运行;
也有些时候这些调用是在某些库或框架里写的,改不了它们的代码但又不想被这些调用干扰也会用这参数。

开启这个参数会有什么坑?
比如Netty中的NIO,使用的是direct memory(不在gc回收范围内),经常、反复的申请DirectByteBuffer,这时候对内存的回收不调用System.gc()的话,会oom。

-XX+ExplicitGCInvokesConcurrent
该参数只能配合CMS使用,System.gc()还是会触发GC的,只不过不是触发一个完全stop-the-world的full GC,而是一次并发GC周期(只在ygc和两个remark阶段停顿)。

结论:使用-XX:+ExplicitGCInvokesConcurrent,不要用-XX:+DisableExplicitGC

使用JDK6u23之前的版本,这里有个bug,可以升级JDK版本解决
6919638 CMS: ExplicitGCInvokesConcurrent misinteracts with gc locker

-XX:+UseAdaptiveSizePolicy

自适应大小调整:根据对象分配以及存活率自动地对新生代Eden和Survivor空间进行调整以最优化对象老化频率。这种模式下,新生代大小、eden与survivor比例、晋升年老代的对象年龄等参数会被自动调整。

只有Throughput收集器(ParallelOldGC,ParallelGC)才支持自适应大小调整,尝试在非Throughput收集器上启用或禁用自适应大小调整都不会有任何效果,即这种操作是空操作。

即目前HotSpot VM上只有ParallelScavenge系的GC才可以配合-XX:+UseAdaptiveSizePolicy使用;也就是只有-XX:+UseParallelGC或者-XX:+UseParallelOldGC。
因此,在使用CMS的时候,不要使用该参数。

-XX:ConcGCThreads

CMS默认启动的并发线程数是(ParallelGCThreads+3)/4。

当有4个并行线程时,有1个并发线程;当有5~8个并行线程时,有2个并发线程。

ParallelGCThreads表示的是GC并行时使用的线程数,如果新生代使用ParNew,那么ParallelGCThreads也就是新生代GC线程数。默认情况下,当CPU数量小于8时,ParallelGCThreads的值就是CPU的数量,当CPU数量大于8时,ParallelGCThreads的值等于3+5*cpuCount/8。

ParallelGCThreads = (ncpus <= 8) ? ncpus : 3 + ((ncpus * 5) / 8)

可以通过-XX:ConcGCThreads或者-XX:ParallelCMSThreads来指定。

并发是指垃圾收集器和应用程序交替执行,并行是指应用程序停止,同时由多个线程一起执行GC。因此并行回收器不是并发的。因为并行回收器执行时,应用程序完全挂起,不存在交替执行的步骤。

-XX:CMSInitiatingOccupancyFraction

由于CMS收集器不是独占式的回收器,在CMS回收过程中,应用程序仍然在不停地工作。在应用程序工作过程中,又会不断产生垃圾。这些新垃圾在当前CMS回收过程中是无法清除的。同时,因为应用程序没有中断,所以在CMS回收过程中,还应该确保应用程序由足够的内存可用。因此,CMS回收器不会等待堆内存饱和时才进行垃圾回收,而是当堆内存使用率达到某一阈值时便开始进行回收,以确保应用程序在CMS工作中仍然有足够的空间支持应用程序运行。

-XX:CMSInitiatingOccupancyFraction,默认为68,即当年老代的空间使用率达到68%时,会执行一次CMS回收。如果应用程序的内存使用率增长很快,在CMS的执行过程中,已经出现了内存不足,此时,CMS回收就会失败,虚拟机将启动SerialOld串行收集器进行垃圾回收。如果这样,应用程序将完全中断,直到垃圾回收完成,这时,应用程序的停顿时间可能会较长。

因此,根据应用特点,可以对该值进行调优,如果内存增长缓慢,则可以设置一个稍大的值,大的阈值可以有效降低CMS的触发频率,减少年老代回收的次数可以较为明显地改善应用程序性能。

反之,如果应用程序内存使用率增长很快,则应该降低这个阈值,以避免频繁触发年老代串行收集器。

-XX:-ScavengeBeforeFullGC

在使用吞吐量优先的垃圾回收器时(-XX:+UseParallelOldGC或-XX:+UseParallelGC),如果关闭-XX:-ScavengeBeforeFullGC,则hotspot vm在FullGC之前不会进行MinorGC,如果开启的话,FullGC之前会先进行MinorGC,分担一部分原本FullGC要做的工作,使得在这两次独立的GC之间java线程有机会得以运行,从而缩短最大停顿时间,但也拉长了整体的停顿时间。


监控参数

-XX:HeapDumpPath

-XX:HeapDumpPath=/data/logs/heaperr.log.201504301631-XX:+HeapDumpOnOutOfMemoryError

设置为动态参数的话:

-XX:HeapDumpPath=/data/logs/heaperr-$(date +%Y%m%d-%H%M%S).log

其中XX:HeapDumpPath可以设置为一个目录或者一个文件,这里指定文件。

-verbose:gc与-XX:+PrintGC

-XX:+PrintGC 与 -verbose:gc 的功能是一样的,区别在于-XX:+PrintGC是managable的,可以通过jinfo被开启或关闭。
另外,-XX:+PrintGCDetails 在启动脚本可以自动开启-XX:+PrintGC , 如果在命令行使用jinfo开启的话,不会自动开启-XX:+PrintGC


参考:

jvm参数备忘
JVM参数陷阱