JVM GC调优入门
这篇文章会介绍几个常用的调优参数,再通过两个案例介绍如何进行JVM GC调优。阅读这篇文章的前提是假设大家已经对JVM内存模型、JVM的垃圾回收算法、JVM的垃圾回收器都比较熟悉了。
JVM调优是必须的吗?
阅读下面的内容之前首先抛出这个问题:GC调优对于java服务是必须的吗?实际上,我感觉80%的java的程序员在实际工作中都没有碰到过GC调优吧,这是因为多数的Java应用不需要在服务器上进行GC优化,多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题,需要记住一点:GC调优是最后要做的工作。
GC调优的目的可以总结为下面两点:
- 减少对象晋升到老年代的数量
- 减少FullGC的执行时间
减少对象晋升到老年代的数量
分代垃圾回收是Oracle JVM中回收思想。 我们知道在Eden区创建的对象,在from Survivor 复制到to Survivor区之后,达到一定年龄就进入了老年代。有些对象因为比较大就直接进入了老年代。在老年代的GC时间相比于年轻代时间更长。因此,减少对象进入老年代可以降低Full GC的频率
减少FullGC的执行时间
Full GC的时间比Minor GC要长。所以如果执行太长时间的Full GC(超过1秒),就会发生超时错误
- 如果你试着减少老年代的大小来降低Full GC的执行时间,可能会引发OutOfMemoryError或者导致Full GC的频率升高。
- 如果是通过增加老年代的大小来降低Full GC的频率,执行时间将会增加。
影响GC的参数
JVM调优主要用到参数罗列在下面的两张表中。主要分为内存参数和垃圾类型参数。GC优化的过程就是在调试这些参数的过程。
下表是与JVM内存相关的参数:
image.png
比较常用的参数是 -Xms
, -Xmx
和 -XX:NewRatio
下表展示的垃圾收集器类型的可选参数:
image.png
不同的垃圾回收器与老年代年轻代的关系如下:
image.png
还有一个常用的参数是-XX:+PrintGCDetails
通过 -XX:+PrintGCDetails
可以查看具体的GC日志。下面的两张图分别介绍Full GC与Minor GC日志里的各个字段。
监控命令
设置好上面将的参数后,可以通过监控查看我们优化的。监控可以分为命令监控和图形化监控。关于图形化监控可用工具比较常见的有JConsole和VisualVM,可以参考这篇文章。这里不做过多介绍。这节主要介绍个常用的监控命令,在下面的案例中也是有用到的。
jps 命令格式:jps [option] [hostid]
jps命令用于查询正在运行的JVM进程,常用的参数为:
-q:只输出LVMID,省略主类的名称
-m:输出虚拟机进程启动时传给主类main()函数的参数
-l:输出主类的全类名,如果进程执行的是Jar包,输出Jar路径
-v:输出虚拟机进程启动时JVM参数
例子:
image.png
jstack 命令格式:jstack [option] vmid
用于生成当前JVM的所有线程快照,线程快照是虚拟机每一条线程正在执行的方法,目的是定位线程出现长时间停顿的原因。
-F:当正常输出的请求不被响应时,强制输出线程堆栈
-l:除堆栈外,显示关于锁的附加信息
-m:如果调用到本地方法的话,可以显示C/C++的堆栈
例子
image.png
jmap 命令格式:jmap [option] vmid
用于显示当前Java堆和永久代的详细信息(如当前使用的收集器,当前的空间使用率等)
-dump:生成java堆转储快照
-heap:显示java堆详细信息(只在Linux/Solaris下有效)
-F:当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照(只在Linux/Solaris下有效)
-histo:显示堆中对象统计信息
例子
image.png
jstat命令格式:jstat [option vmid [interval[s|ms] [count]]]
jstat可以实时显示本地或远程JVM进程中类装载、内存、垃圾收集、JIT编译等数据
-class:监视类装载、卸载数量、总空间及类装载所耗费的时间
-gc:监听Java堆状况,包括Eden区、两个Survivor区、老年代、永久代等的容量,以用空间、GC时间合计等信息
-gccapacity:监视内容与-gc基本相同,但输出主要关注java堆各个区域使用到的最大和最小空间
-gcutil:监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause:与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
-gcnew:监视新生代GC状况
-gcnewcapacity:监视内同与-gcnew基本相同,输出主要关注使用到的最大和最小空间
-gcold:监视老年代GC情况
-gcoldcapacity:监视内同与-gcold基本相同,输出主要关注使用到的最大和最小空间
-gcpermcapacity:输出永久代使用到最大和最小空间
-compiler:输出JIT编译器编译过的方法、耗时等信息
例子
image.png
命令jstat -gc 309 1000 5代表着:搜集vid为309的java进程的整体gc状态, 每1000ms收集一次,共收集5次
案例
下面两个案例是网友的JVM调优过程,作者过程思路清晰,步步分析到位,在这里分享给大家:
1、CMS调优
2、OOM问题调优
总结
JVM调优在实际工作中用到的比较少,但是这也是作为java程序员必须掌握的基本技能。真正熟练的使用GC调优,是建立在多次进行GC监控和调优的实战经验上的。
下面罗列了几个数据作为参考,如果GC执行时间满足下列所有条件,就没有必要进行GC优化了:
Minor GC执行非常迅速(50ms以内)
Minor GC没有频繁执行(大约10s执行一次)
Full GC执行非常迅速(1s以内)
Full GC没有频繁执行(大约10min执行一次)
PS:如果你要应付面试上的JVM题目。这可以参考这篇文章jvm知识点总览
网友评论