JDK本身为调试内存泄漏问题提供了比较完善的工具。
先用命令jps找出要调试的jvm的进程id(jps这个命令,就是ps命令前面加j,列出所有正在运行的jvm的进程id)。
例如:jps
输出类似下面这样:15976 java_app.jar 7586 startup.jar 22476 Jps 12248 Main 5437 Bootstrap
假设我们要调试的进程id是15976.
如果只是想简单观察一下堆内存的使用情况,可以用命令jmap -histo:live 15976这个命令会输出指定的jvm上当前各个Java类的实例数、占用的内存大小和完整的类名。虚拟机内部类的类名前面有"*"标记。
如果想得到堆内存使用的详细情况,可以用命令jmap -dump:live,format=b,file=/tmp/java_app-heap.bin 15976
这样在/tmp目录下得到一个java_app-heap.bin文件,其中保存的信息就是指定的jvm中堆内存的使用详情。这个二进制文件可以用JDK附带的jhat(Java Heap Analysis Tool)来分析:
jhat -J-Xmx326m /tmp/java_app-heap.bin
这个工具相当耗内存,如果出现了OutOfMemoryException的话,请加大-J-Xmx326m中指定的预留堆内存大小再试。
Jhat会解析堆内存信息转储文件(上面用jmap生成的。bin文件),输出大概像下面这样:
lewis@mgr $ jhat -J-Xmx326m /tmp/java_app-heap.bin Reading from /tmp/java_app-heap.bin……
Dump file created Thu Sep 08 20:08:14 CST 2011 Snapshot read, resolving……
Resolving 71327 objects……
Chasing references, expect 14 dots……
Eliminating duplicate references……
Snapshot resolved. Started HTTP server on port 7000 Server is ready.
注意最后两行:堆内存信息转储文件分析完毕后,jhat并不会将分析结果输出为一个静态文件。
为了方便查找,以及在相关的类之间导航,jhat会启动一个服务,监听7000端口。这时候就可以用浏览器来浏览和分析结果了:在浏览器地址栏里输入:
http://localhost:7000
里面的各个页面都有很多链接,可以在相关的各个类及各种统计数据之间跳转,还是很方便的。