JVM-Tuning-CheatSheet

JVM调试与优化实践清单

本文着重于介绍JVM线上问题定位中常用的调试命令与工具,对于具体的应用案例请参考其他章节。

调试工具

常见的调试工具会提供慢调用自动监听、全局线程比对、热点方法分析等功能。

JVM参数配置分析

基础参数

  • -Xms4g: JVM启动时,分配的最小堆大小4G

垃圾回收参数

其他参数

Tomcat JVM配置

CATALINA_OPTS="-server"
CATALINA_OPTS="${CATALINA_OPTS} -Xms5120m -Xmx5120m"
CATALINA_OPTS="${CATALINA_OPTS} -XX:PermSize=256m -XX:MaxPermSize=256m"
CATALINA_OPTS="${CATALINA_OPTS} -Xmn2500m"
CATALINA_OPTS="${CATALINA_OPTS} -XX:MaxDirectMemorySize=1g"
CATALINA_OPTS="${CATALINA_OPTS} -XX:SurvivorRatio=10"
CATALINA_OPTS="${CATALINA_OPTS} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSMaxAbortablePrecleanTime=5000"
CATALINA_OPTS="${CATALINA_OPTS} -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly"
CATALINA_OPTS="${CATALINA_OPTS} -XX:+ExplicitGCInvokesConcurrent -Dsun.rmi.dgc.client.gcInterval=72000000"
CATALINA_OPTS="${CATALINA_OPTS} -XX:ParallelGCThreads=${CPU_COUNT}"
CATALINA_OPTS="${CATALINA_OPTS} -Xloggc:${MIDDLEWARE_LOGS}/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
CATALINA_OPTS="${CATALINA_OPTS} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${MIDDLEWARE_LOGS}/java.hprof"
CATALINA_OPTS="${CATALINA_OPTS} -Djava.awt.headless=true"
CATALINA_OPTS="${CATALINA_OPTS} -Dsun.net.client.defaultConnectTimeout=10000"
CATALINA_OPTS="${CATALINA_OPTS} -Dsun.net.client.defaultReadTimeout=30000"
CATALINA_OPTS="${CATALINA_OPTS} -DJM.LOG.PATH=${MIDDLEWARE_LOGS}"
CATALINA_OPTS="${CATALINA_OPTS} -Dfile.encoding=${JAVA_FILE_ENCODING}"
CATALINA_OPTS="${CATALINA_OPTS} -Djava.awt.headless=true -Dcom.sun.management.jmxremote.port=1090"
CATALINA_OPTS="${CATALINA_OPTS} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.ssl=false"
CATALINA_OPTS="${CATALINA_OPTS} -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=10.125.59.163"
参数 含义 扩展阅读
-Xms4g
-Xmx4g jvm启动时,允许分配的最大的堆大小:4g
-XX:MetaspaceSize=256m 元数据区默认大小,从JDK8之后,没有Perm区了
-XX:MaxMetaspaceSize=256m 元数据的最大大小
-Xmn2g 分配的年轻代大小:2g
-XX:MaxDirectMemorySize=1g 配置最大的堆外内存 http://hellojava.info/?tag=maxdirectmemorysize
-XX:SurvivorRatio=10 Eden区与Survivor区的大小比值
-XX:+UseConcMarkSweepGC 使用CMS内存收集
-XX:+UseCMSCompactAtFullCollection FULL GC的时候,对年老代的压缩 CMS是不会移动内存的,因此,这个非常容易产生碎片,导致内存不够用,因此,内存的压缩这个时候就会被启用。增加这个参数是个好习惯。可能会影响性能,但是可以消除碎片
-XX:CMSMaxAbortablePrecleanTime=5000 指定CMS-concurrent-abortable-preclean阶段执行的时间,该阶段主要是执行一些预清理,减少应用暂停的时间。但在JDK 5.0+6.0+的版本中有可能会由于JDKbug29导致CMSremark完毕后很久才触发sweeping动作。通过设置-XX: CMSMaxAbortablePrecleanTime=5(单位为ms)来避免, http://shensy.iteye.com/blog/1915227 http://www.blogjava.net/BlueDavy/archive/2009/10/09/297562.html
-XX:+CMSClassUnloadingEnabled 由于使用的框架是Spring/Hibernate大量采用cglib,导致生成的Proxy会比较多,而这些是存放在PermGen区域,sun JDK默认情况下不会去回收,必须加上-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled参数,JDK才会去回收这部分数据
-XX:CMSInitiatingOccupancyFraction=80 使用cms作为垃圾回收使用80%后开始CMS收集
-XX:+UseCMSInitiatingOccupancyOnly 我们用-XX+UseCMSInitiatingOccupancyOnly标志来命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期。而是,当该标志被开启时,JVM通过CMSInitiatingOccupancyFraction的值进行每一次CMS收集,而不仅仅是第一次。然而,请记住大多数情况下,JVM比我们自己能作出更好的垃圾收集决策。因此,只有当我们充足的理由(比如测试)并且对应用程序产生的对象的生命周期有深刻的认知时,才应该使用该标志
-XX:+ExplicitGCInvokesConcurrent 如今,被广泛接受的最佳实践是避免显式地调用GC(所谓的“系统GC”),即在应用程序中调用system.gc()。然而,这个建议是不管使用的GC算法的,值得一提的是,当使用CMS收集器时,系统GC将是一件很不幸的事,因为它默认会触发一次Full GC。幸运的是,有一种方式可以改变默认设置。标志-XX:+ExplicitGCInvokesConcurrent命令JVM无论什么时候调用系统GC,都执行CMS GC,而不是Full GC -
-Dsun.rmi.dgc.server.gcInterval=2592000000 作为rmi-server时,gc的时间间隔,默认是1小时,720小时 https://coderanch.com/t/91073/Difference-client-gcInterval-server-gcInterval
-Dsun.rmi.dgc.client.gcInterval=2592000000 作为rmi-client时,gc的时间间隔,默认是1小时,720小时 https://coderanch.com/t/91073/Difference-client-gcInterval-server-gcInterval
-XX:ParallelGCThreads=4 并行收集器的线程数 此值最好配置与处理器数目相等 同样适用于CMS
-Xloggc:/home/admin/logs/gc.log gc打印的日志目录 -
-XX:+PrintGCDetails 打印GC的详情信息 -
-XX:+PrintGCDateStamps 打印GC的时间戳 -
-XX:+HeapDumpOnOutOfMemoryError 当发生OOM错误 时,将内存DUMP下来 -
-XX:HeapDumpPath=/home/admin/logs/java.hprof 内存DUMP的路径 -
-Djava.awt.headless=true Headless模式是在缺少显示屏、键盘或者鼠标时的系统配置 -
-Dsun.net.client.defaultConnectTimeout=10000 java.net.URLConnection默认的连接超时时间,毫秒数单位 -
-Dsun.net.client.defaultReadTimeout=30000 设置超时时间,当从inputstream进行读取的时候 -
-DJM.LOG.PATH=/home/admin/logs 阿里中间件约定定义日志文件路径 -
-DJM.SNAPSHOT.PATH=/home/admin/snapshots 容灾文件,原来和日志一个目录,现在单独指定,防止运维误删,diamond,configclient -
-Dfile.encoding=UTF-8 设置文件编码为UTF-8,Charset.defaultCharset() -
-Dhsf.publish.delayed=true true意思是启动延迟发布,也就是不向configserver上注册地址,等待用户通过online hsf触发将hsf服务地址,注册到configserver,才能提供使用(这种场景下-Dhsf.publish.delayed=trueonline hsf必须同时使用,缺一不可);
-Dproject.name=di-afi 设置工程名,与应用名相同 -
-Dpandora.boot.wait=true PandoraBootstrap.markAndWait(),标记这里是不是要等待的, -
-Dlog4j.defaultInitOverride=true 检查系统属性log4j.defaultInitOverride,如果该属性被设置为false,则执行初始化;否则(只要不是false,无论是什么值,甚至没有值,都是否则,跳过初始化, -
-Dpandora.location=/home/admin/di-afi/target/taobao-hsf.sar 设置潘多拉的路径 -
-Dapp.location=/home/admin/di-afi/target/di-afi 设置应用的路径 -
-Djava.endorsed.dirs 包升级替换机制,一般默认是lib/endorsed文件夹,就是说,可以把你自己的jar包放在这里,代替原有的系统的jar -
-Djava.io.tmpdir=/home/admin/di-afi/.default/temp 设置应用的写入的临时文件目录 -

内存分析

Full GC每小时小于个位数

线程与调用分析

追踪

JVM常用调试命令与工具介绍

本文着重于介绍JVM线上问题定位中常用的调试命令与工具,对于具体的应用案例请参考其他章节。

内存

Full GC每小时小于个位数

Dump

JEP 328: Flight Recorder(JFR)是Oracle刚刚开源的强大特性。而JFR是一套集成进入JDKJVM内部的事件机制框架,通过良好架构和设计的框架,硬件层面的极致优化,生产环境的广泛验证,它可以做到极致的可靠和低开销。在SPECjbb2015等基准测试中,JFR的性能开销最大不超过1%

# Time-Based
$ java -XX:StartFlightRecording=delay=20s,duration=60s,filename=C:\myRecording.jfr,settings=profile,name=SampleRecording

# Continuous With Dump on Demand
$ java -XX:StartFlightRecording=settings=default

# Continuous With Dump on Exit
$ java -XX:StartFlightRecording=settings=default -XX:FlightRecorderOptions=dumponexit=true,dumponexitpath=C:\tmp

通过jmap命令生成dump文件 命令格式:jmap -dump:live,format=b,file=heap.bin 注意:如果要保留heapdump中的不可达对象,则需要把”:live“去掉,即使用命令”jmap -dump,format=b,file=heap.bin “ 通过设置JVM参数自动生成 使用-XX:+HeapDumpOnOutOfMemoryError这个JVM参数,在Java进程运行过程中发生OOM的时候就会生成一个heapdump文件,并写入到指定目录,一般用-XX:HeapDumpPath=${HOME}/logs/test来设置。

线程

网络

磁盘

追踪

Links

诊断Java代码中常见的数据库性能热点问题 大神手把手教你Java性能优化-江南白衣(加强版)