何时该调优JVM
- 堆内存(老年代)持续上涨达到设置的最大内存值
- Full GC 次数频繁
- GC 停顿时间过长(超过1秒)
- 应用出现OutOfMemory等内存异常
- 应用中有使用本地缓存且占用大量内存空间
- 系统吞吐量与响应性能不高或不降
JVM调优的基本原则
JVM调优是一个手段,但并不一定所有问题都可以通过JVM进行调优解决;因此,在进行JVM调优时,我们要遵循一些原则:
- 大多数的Java应用不需要进行JVM优化
- 大多数导致GC问题的原因是代码层面的问题导致的(代码层面)
- 上线之前,应先考虑将机器的JVM参数设置到最优
- 减少创建对象的数量(代码层面)
- 减少使用全局变量和大对象(代码层面)
- 优先架构调优和代码调优,JVM优化是不得已的手段(代码、架构层面)
- 分析GC情况优化代码比优化JVM参数更好(代码层面)
其实最有效的优化手段是架构和代码层面的优化,而JVM优化则是最后不得已的手段。
JVM调优目标
调优的最终目的都是为了令应用程序使用最小的硬件消耗来承载更大的吞吐。JVM调优主要是针对垃圾收集器的收集性能优化,令运行在虚拟机上的应用能够使用更少的内存以及延迟获取更大的吞吐量。
量化目标:
- 堆内存使用率 <= 70%
- 老年代内存使用率 <= 70%
- 平均垃圾回收时间 <= 1秒
- Full GC 次数 0 或 平均回收间隔 >= 24小时
常用的查看JVM堆内存使用情况工具
- jconsole(jdk自带)
- VisualVM(jdk自带)
- jmap:jmap -heap (jdk自带)
- Arthas(阿里)
- Eclipse Memory Analyzer Tool:分析dump文件
调优参数
- Xms:堆内存初始值,使用方法:-Xms1024m 或 -XX:InitialHeapSize=1024m
- Xmx:堆内存最大值,使用方法:-Xmx2048m 或 -XX:MaxHeapSize=2048m
- Xmn:新生代最大值,使用方法:-Xmx512m 或 -XX:MaxNewSize=512m
- MetaspaceSize:元空间初始大小,例如-XX:MetaspaceSize=128m
- MaxMetaspaceSize:元空间最值小,例如-XX:MaxMetaspaceSize=256m
- Xss:线程栈最大值,例如-Xss256k 或 -XX:ThreadStackSize=256k
- MaxDirectMemorySize:最大直接内存(堆外)大小,使用方法:-XX:MaxDirectMemorySize=256m
- NewRatio:老年代和新生代的比值。使用方法:-XX:NewRatio=2。假如设为2,则表示老年代最大内存占堆最大内存的2/3,新生代则为1/3。如果设置了Xmn,那么NewRatio配置无效
- SurvivorRatio:新生代中eden区和survivor区的比值。使用方法:-XX:SurvivorRatio=6。假如设为6,则表示每个survivor区跟eden区的比值为1:6,每个survivor区占新生代的八分之一
- MaxTenuringThreshold:使用方法:-XX:MaxTenuringThreshold=10。每个对象在经历过一次Minor GC之后,年龄就增加1,当超过这个参数值时就进入老年代
辅助定位问题参数
- Xloggc:GC日志文件路径,使用方法:-Xloggc:/data/gclog/gc.log
- PrintGCDetails:GC时打印更多详细信息,默认关闭。使用方法:开启 -XX:+PrintGCDetails,可以通过jinfo -flag [+|-]PrintGCDetails 或 jinfo -flag PrintGCDetails= 来动态开启或设置值
- PrintGCDateStamps:GC时打印时间戳信息,默认关闭。使用方法:开启 -XX:+PrintGCDateStamps,可以通过jinfo -flag [+|-]PrintGCDateStamps 或 jinfo -flag PrintGCDateStamps= 来动态开启或设置值
- PrintTenuringDistribution:打印存活实例年龄信息,默认关闭。使用方法:开启 -XX:+PrintTenuringDistribution
- PrintGCApplicationStoppedTime:打印应用暂停时间,默认关闭。使用方法:开启 -XX:+PrintGCApplicationStoppedTime
- PrintHeapAtGC:GC前后打印堆区使用信息,默认关闭。使用方法:开启 -XX:+PrintHeapAtGC
- HeapDumpOnOutOfMemoryError:抛出内存溢出错误时导出堆信息到指定文件,默认关闭。使用方法:开启 -XX:+HeapDumpOnOutOfMemoryError,可以通过jinfo -flag [+|-]HeapDumpOnOutOfMemoryError 或 jinfo -flag HeapDumpOnOutOfMemoryError= 来动态开启或设置值
- HeapDumpPath:当HeapDumpOnOutOfMemoryError开启的时候,dump文件的保存路径,默认为工作目录下的java_pid.hprof文件。使用方法:-XX:HeapDumpPath=/data/dump/jvm.dump