赞
踩
jstat 是JDK中提供的一个命令行工具,主要用来打印JVM 性能数据相关的统计数据。主要包含以下几个方面:
垃圾回收(GC)方面数据
编译(Compilation)相关数据
类加载信息(Class Loader)
jstat 最大的优势就是可以在JVM运行时,实时的抓取这些数据。
如何启动 jstat
jstat 使用很简单,只要在命令行中执行如下命令:
jstat -gc -t 11256 10000 10
参数解释:
-gc :打印相关的统计参数
-t: 在每行日志之前加上JVM的启动时间
11256 : 目标Java进程的ID
10000: jstat命令执行间隔时间(milliseconds),10000表示每10s打印一行日志
10: jstat命令的执行次数,(和上面的时间间隔一起,表示jstat会每10s执行1次,总共执行10次).
执行结果:
上面命令行执行后的结果类似于以下格式:
jstat 打印的信息很多且杂,要了解其中各部分代表的意义需要先对JVM中堆内存有一定的了解。在JVM中,堆内存分为年轻代和老年代;年轻代因为使用复制回收算法,也被分为Eden区
、S0区
和 S1区
,如下图所示:
了解了堆内存的分布,再看jstat的打印参数就很容易理解了。
参数意义:
time : JVM启动时间(单位为秒)
S0C :年轻代中S0区的容量 (字节)
S1C :年轻代中S1区的容量 (字节)
S0U :年轻代中S0区目前已使用空间 (字节)
S1U :年轻代中S1区目前已使用空间 (字节)
EC :年轻代中Eden区的容量 (字节)
EU :年轻代中Eden区目前已使用空间 (字节)
OC :老年代的容量 (字节)
OU :老年代目前已使用空间 (字节)
YGC :从应用程序启动到采样时年轻代中GC次数
YGCT :从应用程序启动到采样时年轻代中GC所用时间(s)
FGC :从应用程序启动到采样时老年代(全GC)GC次数
FGCT :从应用程序启动到采样时老年代(全GC)GC所用时间(s)
GCT:从应用程序启动到采样时GC用的总时间(s)
解析执行结果
通过上面的jstat打印日志,基本可以得出如下结论:
注意:其实除了 -gc 之外,jstat 还有很多其它子命令
实战演练
我一般使用 jstat 做两个用途
通过查看 jstat 打印的数据,调整JVM配置参数
查看代码中是否存在内存泄漏
1. 调整JVM配置参数
如下代码 JstatDemo.java:
-
- public class JstatDemo {
- static volatile List pigs = new ArrayList();
- static volatile int pigsEaten = 0;
- static final int ENOUGH_PIGS = 1000;
-
- public static void main(String[] args) throws InterruptedException {
- new PigEater().start();
- new PigDigester().start();
- }
-
- static class PigEater extends Thread {
- @Override
- public void run() {
- while (true) {
- pigs.add(new byte[32 * 1024 * 1024]); //32MB
- if (pigsEaten > ENOUGH_PIGS) return;
- sleep(100);
- }
- }
- }
-
- static class PigDigester extends Thread {
- @Override
- public void run() {
- long start = System.currentTimeMillis();
-
- while (true) {
- sleep(2000);
- pigsEaten+=pigs.size();
- pigs = new ArrayList();
- if (pigsEaten > ENOUGH_PIGS) {
- System.out.format("Digested %d pigs in %d ms.%n",pigsEaten, System.currentTimeMillis()-start);
- return;
- }
- }
- }
- }
- static void sleep(int ms) {
- try {
- Thread.sleep(ms);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- 亲爱的小伙伴们,有需要java面试文档资料的请点赞收藏和转发哦,关注我之后点进我的主页右上角私信(555)即刻领取免费资料哦或点击:https://shimo.im/docs/aBAYVxlBX6IDge3j
上述代码分别使用两个线程 PigEater 和 PigEater 来代表线程执行的吞吐量。
接下来通过配置不同JVM配置,分别执行上述代码,并查看代码执行效果。
配置1:
设置堆内存大小为4G (-Xms4g –Xmx4g)
使用CMS回收器回收老年代(-XX:+UseConcMarkSweepGC),使用Parallel回收算法回收年轻代(-XX:+UseParNewGC)
设置年轻代Eden区大小为512M(-Xmn512m)
配置2:
设置堆内存大小为2G(-Xms2g –Xmx2g)
使用Parallel回收器回收年轻代和老年代垃圾对象 (-XX:+UseParallelGC)
设置年轻代Eden区为1536M(-Xmn1536m)
分别通过如下两个命令执行配置1和配置2代码,在执行过程中同时执行 jstat 命令
执行结果为:
可以看出配置2的执行时间更短,执行效率更高。可是配置1的分配内存是配置2的2倍,按照正常思维应该更快一些,而结果却是相反。这是为什么呢?如果要分析原因,可以借助于 jstat 工具来分析。
配置1执行 jstat 结果如下:
- Timestamp S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
- 594.0 174720.0 174720.0 163844.1 0.0 174848.0 131074.1 3670016.0 2621693.5 21248.0 2580.9 1006 63.182 116 0.236 63.419
- 595.0 174720.0 174720.0 163842.1 0.0 174848.0 65538.0 3670016.0 3047677.9 21248.0 2580.9 1008 63.310 117 0.236 63.546
- 596.1 174720.0 174720.0 98308.0 163842.1 174848.0 163844.2 3670016.0 491772.9 21248.0 2580.9 1010 63.354 118 0.240 63.595
- 597.0 174720.0 174720.0 0.0 163840.1 174848.0 131074.1 3670016.0 688380.1 21248.0 2580.9 1011 63.482 118 0.240 63.723
配置2执行 jstat 结果如下:
- Timestamp S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
- 539.3 164352.0 164352.0 0.0 0.0 1211904.0 98306.0 524288.0 164352.2 21504.0 2579.2 27 2.969 141 8.441 11.409
- 540.3 164352.0 164352.0 0.0 0.0 1211904.0 425986.2 524288.0 164352.2 21504.0 2579.2 27 2.969 141 8.441 11.409
- 541.4 164352.0 164352.0 0.0 0.0 1211904.0 720900.4 524288.0 164352.2 21504.0 2579.2 27 2.969 141 8.441 11.409
- 542.3 164352.0 164352.0 0.0 0.0 1211904.0 1015812.6 524288.0 164352.2 21504.0 2579.2 27 2.969 141 8.441 11.409
仔细看可以看出配置1经历了1129次GC事件(YGC + FGC),用时63.723秒(YGCT + FGCT)。而配置2只是经历了168次GC回收,用时11.409秒。大量的GC会造成程序性能降低。
结论:
虽然配置2比配置1的内存小1倍,但是吞吐量却比配置1更高。因此JVM参数的配置还是要根据实际项目、实际情况。
2. 查看代码是否存在内存泄漏
在长时间运行的Java程序中,可以通过运行 jstat 命令连续获取多行GC相关数据,并取这几行数据中的OU(也就是老年代已用容量)的值。
然后,每隔一段较长时间重复一次上述操作,来获取多组OU值。如果这些值呈上升趋势,则说明该Java程序的老年代内存已使用量不断上涨,因此无法被回收的对象在不断增长,很有可能存在内存泄漏。
jstat 缺陷
很明显 jstat 也不是万能的,最大缺陷就是GC日志不详细。
主要有以下几个方面的信息 jstat 无法获取:
当多个GC事件发生时,无法获取某单个GC的pause时间
无法获取sys和user的执行时间
每次GC事件后,有多少内存被回收掉
因此实际分析问题时,还需要结合其它工具一起分析JVM的性能,其它工具后续会持续介绍。
如果本文对你有帮助,别忘了关注,点赞,评论,转发,收藏哟!
收藏等于白嫖,点赞才是真爱 谢谢0.0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。