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

  里面的各个页面都有很多链接,可以在相关的各个类及各种统计数据之间跳转,还是很方便的。