-XX:-UseBiasedLocking
取消偏向锁,JDK1.6开始默认打开的偏向锁,会尝试把锁赋给第一个访问它的线程,取消同步块上的synchronized原语。如果始终只有一条线程在访问它,就成功略过同步操作以获得性能提升。
-XX:+ExplicitGCInvokesConcurrent 但不要-XX:+DisableExplicitGC
full gc时,使用CMS算法,不是全程停顿,必选。
但像R大说的,System GC是保护机制(如堆外内存满时清理它的堆内引用对象),禁了system.gc() 未必是好事,只要没用什么特别烂的类库,真有人调了总有调的原因,所以不应该加这个烂大街的参数。
-XX:MaxTenuringThreshold=2
对象在Survivor区最多熬过多少次Young GC后晋升到年老代,JDK8里CMS 默认是6,其他如G1是15。
Young GC是最大的应用停顿来源,而新生代里GC后存活对象的多少又直接影响停顿的时间,所以如果清楚Young GC的执行频率和应用里大部分临时对象的最长生命周期,可以把它设的更短一点,让其实不是临时对象的新生代对象赶紧晋升到年老代,别呆着。
用-XX:+PrintTenuringDistribution观察下,如果后面几代的大小总是差不多,证明过了某个年龄后的对象总能晋升到老生代,就可以把晋升阈值设小,比如JMeter里2就足够了。
-XX:AutoBoxCacheMax=20000
加大Integer Cache
-Xmx, -Xms
堆内存大小,2~4G均可。
-Xmn
JDK默认新生代占堆大小的1/3, 可以各50%, 因为增大新生代能减少GC的频率,如果老生代里没多少长期对象的话,占2/3通常太多了。
可以用-Xmn 直接赋值(等于-XX:NewSize and -XX:MaxNewSize同值的缩写),或把NewRatio设为1来对半分。
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m (JDK8)
根据情况设置合适的初始值和最大值
-Xss
在堆之外,线程占用栈内存,默认每条线程为1M(以前是256K)。存放方法调用出参入参的栈,局部变量,标量替换后掉局部变量等,有人喜欢把它设回256k,节约内存并开更多线程,有人则会在遇到错误后把它再设大点,特别是有很深的JSON解析之类的递归调用时。
-XX:MaxDirectMemorySize
堆外内存的最大值,默认为Heap区总内存减去一个Survivor区的大小,如果肯定用不了这么多,也可以把它主动设小,来获得一个比较清晰内存占用预估值,特别是在容器里。
-XX:ReservedCodeCacheSize
JIT编译后二进制代码的存放区,满了之后就不再编译,对性能影响很大。初始值为2M, 不开多层编译时最大值为48M,开了的话JDK7是96M,JDK8是240M。可以在JMX里看看CodeCache的占用情况,也可以用VJTools里的vjtop来看,JDK7下默认的48M可以设大点,不抠这么点。
-XX:+PrintCommandLineFlags
运维有时会对启动参数做一些临时的更改,将每次启动的参数输出到stdout,将来有据可查。 打印出来的是命令行里设置了的参数以及因为这些参数隐式影响的参数,比如开了CMS后,-XX:+UseParNewGC也被自动打开。
-XX:ErrorFile
JVM crash时,hotspot 会生成一个error文件,提供JVM状态信息的细节。如前所述,将其输出到固定目录,避免到时会到处找这文件。文件名中的%p会被自动替换为应用的PID
-XX:ErrorFile=${MYLOGDIR}/hs_err_%p.log
-XX:+HeapDumpOnOutOfMemoryError
在Out Of Memory,JVM快死掉的时候,输出Heap Dump到指定文件。不然开发很多时候还真不知道怎么重现错误。
路径只指向目录,JVM会保持文件名的唯一性,叫java_pid${pid}.hprof。因为如果指向文件,而文件已存在,反而不能写入。
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOGDIR}/
但在容器环境下,输出4G的HeapDump,在普通硬盘上会造成20秒以上的硬盘IO跑满,需要注意一下,这个也会影响同一宿主机上的其他容器。
-Xloggc:/dev/xxx/gc.log -XX:+PrintGCDateStamps -XX:+PrintGCDetails
GC的日志实际上对系统性能影响不大,打日志对排查GC问题很重要。
后来又发现如果遇上高IO的情况,GC时操作系统正在flush pageCache 到磁盘,也可能导致GC log文件被锁住,从而让GC结束不了。所以把它指向了/dev/shm 这种内存中文件系统,避免这种停顿,详见Eliminating Large JVM GC Pauses Caused by Background IO Traffic
用PrintGCDateStamps而不是PrintGCTimeStamps,打印可读的日期而不是时间戳。
-XX:+PrintGCApplicationStoppedTime
这是个非常非常重要的参数,但它的名字没起好,其实除了打印清晰的完整的GC停顿时间外,还可以打印其他的JVM停顿时间,比如取消偏向锁,class 被agent redefine,code deoptimization等等,有助于发现一些原来没想到的问题。如果真的发现了一些不知是什么的停顿,需要打印安全点日志找原因。
Dump相关参数
-XX:+HeapDumpOnOutOfMemoryError
当OutOfMemoryError发生时自动生成 Heap Dump 文件。
这是一个非常有用的参数,因为当你需要分析Java内存使用情况时,往往是在OOM(OutOfMemoryError)发生时。
-XX:+HeapDumpBeforeFullGC
当 JVM 执行 FullGC 前执行 dump。
-XX:+HeapDumpAfterFullGC
当 JVM 执行 FullGC 后执行 dump。
-XX:+HeapDumpOnCtrlBreak
交互式获取dump。在控制台按下快捷键Ctrl + Break时,JVM就会转存一下堆快照。
-XX:HeapDumpPath=d:\test.hprof
指定 dump 文件存储路径。