JVM调优工具
JMap
首先要知道Java进程的pid。
Windows:
..
..
..
Linux:
ps -ef | grep java
查看堆栈信息(jmap -heap pid)
jmap -heap 8512 Attaching to process ID 8512, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.161-b12 using thread-local object allocation. Parallel GC with 8 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 2128609280 (2030.0MB) NewSize = 44564480 (42.5MB) MaxNewSize = 709361664 (676.5MB) OldSize = 89653248 (85.5MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 68157440 (65.0MB) used = 57053032 (54.410011291503906MB) free = 11104408 (10.589988708496094MB) 83.70770967923679% used From Space: capacity = 5242880 (5.0MB) used = 3113008 (2.9687957763671875MB) free = 2129872 (2.0312042236328125MB) 59.37591552734375% used To Space: capacity = 3670016 (3.5MB) used = 0 (0.0MB) free = 3670016 (3.5MB) 0.0% used PS Old Generation capacity = 89653248 (85.5MB) used = 49152 (0.046875MB) free = 89604096 (85.453125MB) 0.05482456140350877% used 3998 interned Strings occupying 342784 bytes.
打印等待回收的对象信息(jmap -finalizerinfo pid)
jmap -finalizerinfo 8512 Attaching to process ID 8512, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.161-b12 Number of objects pending for finalization: 0
打印堆里面对象的统计信息:对象数量、占用大小、类名(jmap -histo:live pid | more)
jmap -histo:live 8512 | more num #instances #bytes class name ---------------------------------------------- 1: 9728 1016408 [C 2: 1650 303784 [B 3: 9441 226584 java.lang.String 4: 1821 205672 java.lang.Class 5: 1285 92520 org.apache.zookeeper.data.StatPersisted 6: 1735 87008 [Ljava.lang.Object; 7: 2385 76320 java.util.HashMap$Node 8: 2322 74304 java.util.concurrent.ConcurrentHashMap$Node 9: 1199 57552 java.util.HashMap 10: 783 54312 [I 11: 658 45208 [Ljava.util.HashMap$Node; 12: 1285 41120 org.apache.zookeeper.server.DataNode 13: 437 38456 java.lang.reflect.Method 14: 502 36144 org.apache.zookeeper.server.Request 15: 882 35280 java.util.TreeMap$Entry 16: 501 24048 org.apache.zookeeper.txn.TxnHeader 17: 889 21336 java.util.LinkedList$Node 18: 582 21296 [Ljava.lang.String; 19: 1049 16784 java.util.HashSet 20: 501 16032 org.apache.zookeeper.server.quorum.QuorumPacket 21: 399 15960 java.lang.ref.SoftReference 22: 31 15952 [Ljava.util.concurrent.ConcurrentHashMap$Node;
打印类加载器统计信息(jmap -clstats pid)
jmap -clstats 8512 Attaching to process ID 8512, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.161-b12 finding class loader instances ..done. computing per loader stat ..done. please wait.. computing liveness....................................liveness analysis may be inaccurate ... class_loader classes bytes parent_loader alive? type <bootstrap> 1359 2420845 null live <internal> 0x000000008128cef8 1 1474 null dead sun/reflect/DelegatingClassLoader@0x0000000017289df8 0x000000008128d088 1 880 null dead sun/reflect/DelegatingClassLoader@0x0000000017289df8 0x000000008128d218 1 880 null dead sun/reflect/DelegatingClassLoader@0x0000000017289df8 0x00000000814621d0 0 0 0x000000008120b6c8 dead java/util/ResourceBundle$RBClassLoader@0x0000000017303798 0x000000008120b6c8 358 716069 0x000000008120b728 live sun/misc/Launcher$AppClassLoader@0x000000001728f6a0 0x000000008120b728 3 2574 null live sun/misc/Launcher$ExtClassLoader@0x000000001728fa48 0x000000008128cfc0 1 880 null dead sun/reflect/DelegatingClassLoader@0x0000000017289df8 0x000000008128d150 1 880 null dead sun/reflect/DelegatingClassLoader@0x0000000017289df8 total = 9 1725 3144482 N/A alive=3, dead=6 N/A
把堆信息生成一个文件(jmap -dump:live,format=b,file=heap.bin <pid>)
[d:\]$ jmap -dump:live,format=b,file=heap.bin 8512 Dumping heap to D:\heap.bin ... Heap dump file created
之后,我们利用Mat来分析,下载 Eclipse Memory Analyzer
..
下载完解压
...
..
..
..打开我们刚才生成的文件
..
..看效果
..
JStat
每隔一段时间输出GC情况(jstat -gcutil pid inteval)
[d:\]$ jstat -gcutil 8512 3000 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082 0.00 0.00 0.94 7.26 96.88 93.14 7 0.061 2 0.022 0.082
参数:
S0 from区已使用容量的百分比
S1 to区已使用容量的百分比
E 伊甸区已使用容量的百分比
O 老年代已使用容量的百分比
M 元数据空间利用率
CCS 压缩类空间利用率
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)
还有另外一个方法,输出的要全面一些
[d:\]$ jstat -gc 8512 3000 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 4096.0 3584.0 0.0 0.0 133120.0 1257.0 37376.0 2715.3 9600.0 9300.8 1152.0 1073.0 7 0.061 2 0.022 0.082 4096.0 3584.0 0.0 0.0 133120.0 1257.0 37376.0 2715.3 9600.0 9300.8 1152.0 1073.0 7 0.061 2 0.022 0.082 4096.0 3584.0 0.0 0.0 133120.0 1257.0 37376.0 2715.3 9600.0 9300.8 1152.0 1073.0 7 0.061 2 0.022 0.082 4096.0 3584.0 0.0 0.0 133120.0 1257.0 37376.0 2715.3 9600.0 9300.8 1152.0 1073.0 7 0.061 2 0.022 0.082
参数:
S0C: 当前from区容量
S1C: 当前to区容量
S0U: from区已使用的容量
S1U: to区已使用的容量
EC: 当前伊甸区的容量
EU: 伊甸区已使用的容量
OC: 老年代的容量
OU: 老年代已使用的容量
MC: 元空间容量
MU: 元空间已使用容量
CCSC: 压缩类空间容量
CCSU: 已使用的压缩类空间
YGC: 年轻代gc次数
YGCT: 年轻代gc时间
FGC: full gc 次数
FGCT: Full gc时间
GCT: 总gc时间
场景:Full GC时间很长,并且GC之前堆内存是稳步上升的
要么是内存泄漏,要么是垃圾回收出了问题。
第一步你要看一下堆里对象是否异常
jmap -histo:live 【pid】 | more
然后看一下GC情况是否出现了异常的回收时间
jstat -gc 【pid】【interval】
再看一下内存分配是否出现了问题
jmap -heap 【pid】
有的服务器上不能直接使用jmap的命令,我们可以定位到java的bin目录,然后执行./jmap
利用 echo $JAVA_HOME 将JDk目录显示出来,去找个目录里找即可
*********************内存排查
1. ./jmap -heap pid
2. ./jmap -histo:live pid | more
3. ./jmap -dump:live,format=b,file=/home/a.dump pid
4. 用jvisualvm查看堆信息
*********************CPU排查
1. top命令,找出CPU占用最高的
2. ps aux | grep [pid] 确定程序
3. ps -mp [pid] -o THREAD,tid,time 显示线程列表
4. printf "%x\n" tid 线程ID转换成16进制
5. jstack [pid] | grep [tid] -A 30 打印堆栈信息或者:
1. top命令,找出CPU占用最高的[pid]
2. jstack [pid] > /home/t.txt 导出堆栈
3. top -H -p [pid] 查看进程里线程占用CPU情况,获取 tid
4. printf "%x\n" tid 线程ID转换成16进制
5. jstack 导出的文件中找到转换后的关键字*********************
GC日志
你可以在启动参数里加上 -XX:+PrintGCDetails 这样在发生GC就会打印日志
可以利用 ps -ef | grep java 查看启动参数
测试
public static void main(String[] args) throws Exception { List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10000000; i++){ list.add(i); } Thread.sleep(10000); System.out.println("==================Exit=================="); }
在IDEA里的Edit Configurations设置
运行一遍上面代码
[GC pause (G1 Evacuation Pause) (young), 0.0435845 secs] [Eden: 20.0M(20.0M)->0.0B(3072.0K) Survivors: 0.0B->3072.0K Heap: 32.7M(128.0M)->28.8M(128.0M)] ... [GC pause (G1 Evacuation Pause) (young), 0.0299648 secs] [Eden: 3072.0K(3072.0K)->0.0B(11.0M) Survivors: 3072.0K->1024.0K Heap: 31.8M(128.0M)->34.7M(256.0M)] ... [GC pause (G1 Evacuation Pause) (young), 0.0356263 secs] [Eden: 11.0M(11.0M)->0.0B(23.0M) Survivors: 1024.0K->2048.0K Heap: 63.1M(256.0M)->64.6M(512.0M)] ... [GC pause (G1 Evacuation Pause) (young), 0.0447098 secs] [Eden: 23.0M(23.0M)->0.0B(36.0M) Survivors: 2048.0K->4096.0K Heap: 103.2M(512.0M)->105.2M(816.0M)] ... [GC pause (G1 Evacuation Pause) (young), 0.0506044 secs] [Eden: 36.0M(36.0M)->0.0B(47.0M) Survivors: 4096.0K->5120.0K Heap: 164.7M(816.0M)->167.7M(1059.0M)] ... [GC pause (G1 Evacuation Pause) (young), 0.0679058 secs] [Eden: 47.0M(47.0M)->0.0B(55.0M) Survivors: 5120.0K->7168.0K Heap: 249.9M(1059.0M)->251.4M(1254.0M)] ==================Exit================== Heap garbage-first heap total 1284096K, used 330981K [0x0000000081200000, 0x0000000081302730, 0x0000000100000000) region size 1024K, 27 young (27648K), 7 survivors (7168K) Metaspace used 3995K, capacity 4568K, committed 4864K, reserved 1056768K class space used 435K, capacity 460K, committed 512K, reserved 1048576K
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCDateStamps 输出GC的时间
-XX:+PrintHeapAtGC GC的前后打印出堆的信息
-Xloggc:../logs/gc.log 日志文件的输出路径
参考:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jstat.html