Java虚拟机五:常用内存分析命令和工具
一、常用命令
1、jps
jps(JVM Process Status),可以列出虚拟机内的进程,并显示虚拟机执行主类名称以及这些进程的本地虚拟机唯一ID,该ID与操作系统的进程ID一致,jps命令格式为: jps [options] [hostid]
其中options为该命令的选项,hostid为虚拟机中进程的唯一ID,也是linux下系统中进程的pid,options有如下取值:
选项 | 说明 |
-q | 只显示进程id,不显示主类 |
-m | 输出虚拟机进程启动时传递给主类的参数 |
-l | 列出主类的全名,如果进程执行的是Jar包,则列出Jar包的路径 |
-v | 输出虚拟机进程启动时候的参数 |
命令示例如下:
[root@localhost software]# jps 74946 Jps 65684 Bootstrap [root@localhost software]# jps -q 65684 75052 [root@localhost software]# jps -l 65684 org.apache.catalina.startup.Bootstrap 75160 sun.tools.jps.Jps [root@localhost software]# jps -m 75298 Jps -m 65684 Bootstrap start [root@localhost software]# jps -v 65684 Bootstrap -Djava.util.logging.config.file=/usr/local/tomcat8/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -Dcatalina.base=/usr/local/tomcat8 -Dcatalina.home=/usr/local/tomcat8 -Djava.io.tmpdir=/usr/local/tomcat8/temp 75628 Jps -Denv.class.path=/usr/local/jdk/lib/ -Dapplication.home=/usr/local/jdk -Xms8m [root@localhost software]#
2、jstat
jstat(JVM Statistics Monitoring Tool)命令主要用来监控虚拟机运行状态信息,其命令格式为 jstat [options] [vmid] [interval[m|ms]] [count]
其中,options选项用来确定需要监视虚拟机的哪部分数据,vmid为本地虚拟机进程id,interval用于控制监控的时间间隔,可以加m|ms单位,count用来控制监控的次数。options选项取值如下:
选项 | 说明 |
-class | 监控类装载,卸载数量,总空间以及类装载所耗费的时间 |
-gc | 监视Java堆状况,包括Eden区,两个Survivor区,老年代等的容量,已用空间,GC时间合计等信息 |
-gccapacity | 监视内容与-gc一样,但只要关注Java堆中各个区域使用到的最大,最小空间 |
-gcutil | 监视内容与-gc一样,但只要关注已使用空间占总空间的百分比 |
-gccause | 与-gcutil功能一样,但会额外输出导致上一次GC的原因 |
-gcnew | 监视新生代GC状况 |
-gcnewcapacity | 监视内容与-gcnew一样,但是主要关注使用新生代使用的最大,最小空间 |
-gcold | 监视老年代GC状况 |
-gcoldcapacity | 监视内容与-gcold一样,但是主要关注老年代使用的最大,最小空间 |
-compiler | 输出JIT编译器编译过的方法,耗时等信息 |
-printcompilation | 输出已经被JIT编译的方法 |
命令示例如下:
[root@localhost software]# jstat -gc 65684 1s 2 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 704.0 704.0 0.0 0.0 6016.0 1369.2 14820.0 6365.8 18176.0 17511.6 2048.0 1922.7 12 0.134 2 0.392 0.526 704.0 704.0 0.0 0.0 6016.0 1369.2 14820.0 6365.8 18176.0 17511.6 2048.0 1922.7 12 0.134 2 0.392 0.526 [root@localhost software]# jstat -gcold 65684 1s 2 MC MU CCSC CCSU OC OU YGC FGC FGCT GCT 18176.0 17511.6 2048.0 1922.7 14820.0 6365.8 12 2 0.392 0.526 18176.0 17511.6 2048.0 1922.7 14820.0 6365.8 12 2 0.392 0.526 [root@localhost software]#
3、jmap
jmap命令的主要作用是生成堆转储文件,其命令格式为: jmap [option] vmid
其中,option的取值有如下几种:
选项 | 说明 |
-dump | 用于生成堆转储快照文件,命令格式为:jmap -dump:[live,]format=b,file=<filename>,其中live参数表示只dump出存活的对象,命令示例: jmap -dump:format=b,file=./result.hprof 65684 ;或者 jmap -dump:live,format=b,file=./result.hprof 65684 |
-finalizerinfo | 显示在F-QUeue中等待Finalizer线程执行finalize方法的对象,如: jmap -finalizerinfo 65684 |
-heap | 显示Java堆详细信息,如使用哪种垃圾回收期,参数配置,分代状况等。如: jmap -heap 65684 |
-histo | 显示堆中对象统计信息,包括类,实例数量,合计容量。如: jmap -histo 65684 |
-F | 当虚拟机对-dump命令没有响应的时候,可以使用该参数强制生成dump文件 |
常用例子:
(1)生成dump文件:
[root@localhost software]# jmap -dump:format=b,file=./dumpresult.hprof 65684 Dumping heap to /software/dumpresult.hprof ... Heap dump file created [root@localhost software]#
(2)查看Java堆详细信息:
[root@localhost software]# jmap -heap 65684 Attaching to process ID 65684, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.211-b12 using thread-local object allocation. Mark Sweep Compact GC Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 257949696 (246.0MB) NewSize = 5570560 (5.3125MB) MaxNewSize = 85983232 (82.0MB) OldSize = 11206656 (10.6875MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: New Generation (Eden + 1 Survivor Space): capacity = 6881280 (6.5625MB) used = 1330704 (1.2690582275390625MB) free = 5550576 (5.2934417724609375MB) 19.338030133928573% used Eden Space: capacity = 6160384 (5.875MB) used = 1330704 (1.2690582275390625MB) free = 4829680 (4.6059417724609375MB) 21.60099110704787% used From Space: capacity = 720896 (0.6875MB) used = 0 (0.0MB) free = 720896 (0.6875MB) 0.0% used To Space: capacity = 720896 (0.6875MB) used = 0 (0.0MB) free = 720896 (0.6875MB) 0.0% used tenured generation: capacity = 15175680 (14.47265625MB) used = 6518560 (6.216583251953125MB) free = 8657120 (8.256072998046875MB) 42.953989541160595% used 13442 interned Strings occupying 1162192 bytes. [root@localhost software]#
4、jstack
jstack用于生成虚拟机当前时刻的线程快照(threaddump文件),命令格式为 jstack [option] vmid 。
其中option具体取值如下:
参数 | 说明 |
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 除堆栈外,显示关于锁的信息 |
-m | 如果调用到本地方法的话,可以显示C/C++的堆栈 |
使用 jstack -l 65684>./result.txt 命令,将线程堆栈保存到result.txt中进行分析
5.jcmd
jcmd命令格式为 jcmd [vmid] [option] ,具体的option取值,可以使用 jcmd [vmid] help 命令查看:
[root@localhost software]# jcmd 65684 help 65684: The following commands are available: JFR.stop JFR.start JFR.dump JFR.check VM.native_memory VM.check_commercial_features VM.unlock_commercial_features ManagementAgent.stop ManagementAgent.start_local ManagementAgent.start VM.classloader_stats GC.rotate_log Thread.print GC.class_stats GC.class_histogram GC.heap_dump GC.finalizer_info GC.heap_info GC.run_finalization GC.run VM.uptime VM.dynlibs VM.flags VM.system_properties VM.command_line VM.version help For more information about a specific command use 'help <command>'. [root@localhost software]#
使用示例:使用jcmd打印NativeMemoryTracking,分析堆外内存
首先需要配置JVM参数 -XX:NativeMemoryTracking=[off | summary | detail] 。在tomcat的 catalina.sh 中加入 JAVA_OPTS="-XX:NativeMemoryTracking=detail" ,然后使用命令 jcmd 112352 VM.native_memory summary 查看内存:
[root@localhost bin]# jcmd 112352 VM.native_memory summary 112352: Native Memory Tracking: Total: reserved=1614878KB, committed=85806KB - Java Heap (reserved=251904KB, committed=16384KB) (mmap: reserved=251904KB, committed=16384KB) - Class (reserved=1063348KB, committed=15412KB) (classes #2372) (malloc=436KB #2468) (mmap: reserved=1062912KB, committed=14976KB) - Thread (reserved=42331KB, committed=42331KB) (thread #42) (stack: reserved=42148KB, committed=42148KB) (malloc=135KB #207) (arena=48KB #80) - Code (reserved=250457KB, committed=5605KB) (malloc=857KB #1584) (mmap: reserved=249600KB, committed=4748KB) - GC (reserved=836KB, committed=72KB) (malloc=8KB #109) (mmap: reserved=828KB, committed=64KB) - Compiler (reserved=141KB, committed=141KB) (malloc=10KB #89) (arena=131KB #5) - Internal (reserved=783KB, committed=783KB) (malloc=751KB #3761) (mmap: reserved=32KB, committed=32KB) - Symbol (reserved=4358KB, committed=4358KB) (malloc=2848KB #17221) (arena=1511KB #1) - Native Memory Tracking (reserved=544KB, committed=544KB) (malloc=118KB #1670) (tracking overhead=426KB) - Arena Chunk (reserved=176KB, committed=176KB) (malloc=176KB) [root@localhost bin]#
二、常用工具
MAT(Eclipse Memory Analyzer )是一个Eclipse插件,可以在Eclipse中安装,也可以独立运行。使用MAT进行内存分析非常方便。其下载地址为:https://www.eclipse.org/mat/downloads.php
选择合适的版本下载,解压后即可使用。
要分析内存,首先要获取dump文件,可以通过配置JVM参数 -XX:+HeapDumpOnOutOfMemoryError ,让虚拟机在内存溢出的时候dump出内存快照,也可以使用 jmap -dump:format=b,file=./dumpresult.hprof 65684 命令随时dump出内存快照。
打开MAT后,点击“Open a Heap Dump”选择dump文件,会弹出如下界面:
选择“Leak Suspects Report”生成内存泄漏分析报告:
MAT会以饼图的形式列出发生内存溢出时候,堆内存中占用内存最大的的几个对象。点击“Leak Suspects”查看内存泄漏分析报告:
MAT分析结果认为导致内存泄漏的原因有两点,问题1大意是0xff993af0 http-nio-8080-exec-1这个线程持有的本地变量占用了50.20%的内存,点击Detail可以查看具体的分析结果:
分析结果中列出了内存中对象统计结果,按照类进行统计的结果,可以看到有此时内存中共有com.demo.ssm.entity.User类的对象50428个,这些对象的保留堆大小为15,330,112kb。同时0xfe990000的这个Object中保存了56*20=1120个User对象,而这个Object是被0xffa65ff0这个ArrayList引用的,该Object和ArrayList占用堆内存50.18%。按照这些信息,排查代码中向ArrayList中添加User对象的操作,可以找出内存溢出的原因。
关于MAT的使用要点,可以参考:https://eclipsesource.com/blogs/2013/01/21/10-tips-for-using-the-eclipse-memory-analyzer/