哪些对象可以作为根对象呢?使用eclipse的MAT(memory analyzer)可以进行分析。这个工具比jvisual更加专业,可以找到内存泄漏。
运行如下代码。
/** * 演示GC Roots */ public class Demo2_2 { public static void main(String[] args) throws InterruptedException, IOException { List<Object> list1 = new ArrayList<>(); list1.add("a"); list1.add("b"); System.out.println(1); System.in.read(); list1 = null; System.out.println(2); System.in.read(); System.out.println("end..."); } }
使用命令jps
查看当前运行代码的进程为17332。
PS F:\资料 解密JVM\代码\jvm> jps 13472 Launcher 3296 Jps 12868 RemoteMavenServer36 17332 Demo2_2 11180
在list回收前、后分别使用jamp
抓取目标进程内存的快照,转储为二进制文件,并设置live
参数在抓取快照前主动触发垃圾回收。回收前的操作命令如下。
jmap -dump:format=b,live,file=gcRootDemo.bin 17332
使用elipse的MAT工具可以来分析内存泄漏问题,官网下载安装MAT,https://www.eclipse.org/mat/downloads.php。
使用MAT工具,菜单栏file->open dump file打开刚才抓取的快照文件。打开文件时报错Invalid HPROF file header
,其中一个原因为人工改变了文件的编码格式,重新抓取并不要改变编码格式。将两个文件都打开以方便对照。如下图,查看文件的GC Roots。
可以看到GC Root的具体情况,被分为了4类。
System Class是程序运行所必须的核心类。
第二类是执行本地方法时操作系统所引用的Java对象的类。
Busy Monitor是指正在加锁的对象,如果这对象被回收了,则锁无法被释放,故不会被回收。
最后是活动着的线程中,局部变量所引用的对象不能被当成垃圾回收。比如下图中的ArrayList其实就是对应代码中list1被垃圾回收前所指对象,在list对象回收后的抓取的内存快照gcRootDemo2.bin中该对象不存在了。