在生产环境中,可能会遇到内存占用率达到接近 99%的情况,这时候,如果很清楚加了xxx功能之后出现了此问题,那么排查问题就在新功能上找原因,但是想知道到底是哪些对象比较大,为什么,就得使用JDK提供的一些分析工具了。
常用命令
- jps:查看本机java进程信息
- jstack:打印线程的栈信息,制作线程dump文件
- jmap:打印内存映射,制作堆dump文件
- jhat:内存分析工具
- jstat:性能监控工具
- jconsole:简易的可视化控制台
- jvisualvm:功能强大的控制台
这里是分析内存占用太高,所以以上命令不是全部都涉及到,比如jstack是分析线程的、jvisualvm是控制台等等。
jps
它可以来显示当前所有java进程pid的命令,我们可以通过这个命令来查看到底启动了几个java进程(因为每一个java程序都会独占一个java虚拟机实例),不过jps有个缺点是只能显示当前用户的进程id,要显示其他用户的还只能用linux的ps命令。
比如我本机,输入jps命令,显示所有的java进程,如下:
D:\Java\jdk1.8.0_162\bin>jps
22192 Launcher
6480 RemoteMavenServer
17284 Launcher
19900 Jps
21964 Bootstrap
其中,如果要分析java堆内存,那么对应的是 Bootstrap 的pid。
jps -l
输出应用程序main.class的完整package名或者应用程序jar文件完整路径名:
D:\Java\jdk1.8.0_162\bin>jps -l
22192 org.jetbrains.jps.cmdline.Launcher
6480 org.jetbrains.idea.maven.server.RemoteMavenServer
17284 org.jetbrains.jps.cmdline.Launcher
4520 sun.tools.jps.Jps
21964 org.apache.catalina.startup.Bootstrap
可见,由于我启动了一个tomcat,pid 21964 即tomcat的启动类。
jps -v
输出传递给JVM的参数,可查看参数的配置信息,如图,这是一台服务器的参数数据:
jps 失效
如果jps命令失效,而我们又要获取pid,还可以使用以下两种方法:
- top | grep java
- ps -ef |grep java
jmap
得到pid之后,就可以按pid进行分析了,jmap主要用于打印指定java进程的共享对象内存映射或堆内存细节。
⭐ 堆Dump是反映堆使用情况的内存镜像,其中主要包括系统信息、虚拟机属性、完整的线程Dump、所有类和对象的状态等。一般在内存不足,GC异常等情况下,我们会去怀疑内存泄漏,这个时候就会去打印堆Dump。
jmap pid
打印的信息分别为:共享对象的起始地址、映射大小、共享对象路径的全程:
jmap -heap pid
查看堆使用情况
jmap -histo pid
查看堆中对象数量和大小,打印的信息分别是:序列号、Class实例的数量、内存的占用、类限定名 ⭐ 如果是内部类,类名的开头会加上*,如果加上live子参数的话,如jmap -histo:live pid,这个命名会触发一次FUll GC,只统计存活对象。
jmap -dump
将内存使用的详细情况输出到文件。 命令:
然后使用jhat命令查看该文件:jhat -port 4000 文件名
启动后在浏览器中访问http:localhost:4000/
总结: 该命令适用的场景是程序内存不足或者GC频繁,这时候很可能是内存泄漏。通过以上命令查看堆使用情况、大量对象被持续引用等情况。
作者: Zealon
崇尚简单,一切简单自然的事物都是美好的。