jmap
JDK自带了一些工具可以帮助我们查看JVM运行的堆内存情况,常用的是jmap命令
打印堆的使用情况 看下我的tomcat的jvm占用情况:
jmap -heap <pid>
那么,从这个输出中我们也可以大致看出堆的结构,分为Young Generation (年轻代) 和 Old Generation (老年代)
Young Generation又被划分为:Eden Space , From Space 和 To Space
可以看到这里To区是干净的,还未被使用,From区已经使用了50%了
打印类的实例数量、占用的内存、类的名称,通常我们并不需要看所有的,只需要看前几条即可:
jmap -histo[:live] <pid>
win下前几行比较麻烦:
jmap -histo 20964 | findstr/n ^^|findstr "^[1-9]: ^1[0-9]: ^2[0-9]:"
find /N ^^
在每行的开头添加行号,同时findstr /r \[[0-9]\]
使用正则表达式提取前1-29行。
linux下pid进程号可以通过ps -ef | grep java获取
win10的话直接在任务管理器 进程一栏就可以看到,如果没有可以在列上勾选pid显示。
linux就简单了
jmap -histo 20964 | head
以hprof二进制格式dump堆的使用情况(PS:相当于生成一个快照,后续我们可以对这个快照文件进行分析):
jmap -dump:live,format=b,file=heap.bin <pid>
Memory Analyzer (MAT)
文件dump下来以后,可以使用Eclipse的MAT插件进行查看
如果日常开发用的是eclipse的话,可以直接安装这个插件,如果不是的话,这个插件也可以独立运行
https://www.eclipse.org/mat/
https://www.eclipse.org/mat/downloads.php
解压之后双击MemoryAnalyzer.exe即可运行
打开刚才的heap.bin文件
可以看到下面有三个选项卡,包括可以执行的操作和报表
先看第一个Histogram 直方图
由于这里是随便运行的一个工程,并没有出现内存泄漏之类的问题,所以这里看到的都是一些基础的java类
查看引用
Dominator Tree 可以看到biggest object以及它们所占内存的比例
我们一级一级的找,可以找到源文件,然后分析代码,最终定位到问题之根源
jconsole
JConsole 是一个内置 Java 性能分析器,可以从命令行(直接输入jconsole)或在 GUI shell (jdk\bin下打开)中运行。
它用于对JVM中内存,线程和类等的监控。可使用JTop插件。它可以监控本地的jvm,也可以监控远程的jvm,也可以同时监控几个jvm。
这款工具的好处在于,占用系统资源少,而且结合Jstat,可以有效监控到java内存的变动情况,以及引起变动的原因。在项目追踪内存泄露问题时,很实用。
2.如何启动JConsole
1)如果是从命令行启动,使JDK在PATH上,运行jconsole即可。
2)如果从GUI shell启动,找到JDK安装路径,打开bin文件夹,双击jconsole。
当分析工具弹出时(取决于正在运行的Java版本以及正在运行的Java程序数量),可能会出现一个对话框,要求输入一个进程的URL来连接,也可能列出许多不同的本地Java进程(有时包含JConsole进程本身)来连接。如图所示:
想分析那个程序就双击那个进程。
3.如何设置JAVA程序运行时可以被JConsolse连接分析
本地程序(相对于开启JConsole的计算机),无需设置任何参数就可以被本地开启的JConsole连接(Java SE 6开始无需设置,之前还是需要设置运行时参数-Dcom.sun.management.jmxremote)
无认证连接(下面的设置表示:连接的端口为8999、无需认证就可以被连接)
-Djava.rmi.server.hostname=10.0.0.110(服务器IP)
-Dcom.sun.management.jmxremote.port=8999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=8999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
监控tomcat
1、 修改Tomcat的bin目录下的catalina.bat文件 其实就是添加jvm参数
JAVA_OPTS="${JAVA_OPTS} -Djava.rmi.server.hostname=192.168.56.253 -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.acccess.file=/usr/local/tomcat/bin/jconsole/jmxremote.access -Dcom.sun.management.jmxremote.password.file=/usr/local/tomcat/bin/jconsole/jmxremote.password"
注意:这里是一行,空格不合适可能会启动不了服务。
2.编辑jmxremote.access和jmxremote.password
这两个文件是在JDK里面的,可以通过%JAVA_HOME%/jre/lib/management目录找到。里面有个jmxremote.password.template文件,将其重命名为jmxremote.password,这就是控制远程连接的用户名密码的。
编辑jmxremote.password,解开注释
# Following are two commented-out entries. The "measureRole" role has
# password "QED". The "controlRole" role has password "R&D".
monitorRole QED
controlRole R&D
然后通过客户端去连接刚刚设置的地址与端口,看到远程的jvm实时情况。
Comments | 2 条评论
博主 Chihilo
这里的进程号是根据应用启动的端口去获取的吗?是否可以加上这一部分的操作。只是没弄懂7799咋来的。后续的分析工具的使用说明很直观,感觉博主推荐这么好的工具
博主 Ykuee
@Chihilo win10可以通过任务管理器看到,linux就是ps -ef | grep java