使用方法很简单。在命令终端输入jconsole就会自动弹出来。
上面代码的观测结果如下。
📕 总结:
上面在排查问题时,我们通过加log以及sleep的方式,帮助我们进行dump时间的把握,在实际生产中可以运用类似方式。
除了内存,jconsole还可以监测线程、cpu占用率以及类的数量变化等。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3O31REj-1656678910765)(F:/%E5%8D%9A%E5%AE%A2%E5%9B%BE%E7%89%87/jvm/image-20220630214317498.png)]
还可以帮我们检测死锁。
6.4 多次垃圾回收内存占用仍很高问题的排查
jvisualvm也是一个可视化工具,比jconsole更好用。
使用方法很简单,使用命令which java查找到java安装路径,并切换至该路径,然后在对应路径执行jvisualvm即可。
在高版本JDK(大于1.8或后期更新的1.8版本)中已经不会再自动集成它了。参考博客可以下载独立版:JDK 高版本没有VisualVM_东理羁客的博客-CSDN博客。
下面使用它演示,多次垃圾回收内存占用仍很高问题的排查
/** * 演示查看对象个数 堆转储 dump */ public class Demo1_13 { public static void main(String[] args) throws InterruptedException { List<Student> students = new ArrayList<>(); for (int i = 0; i < 200; i++) { students.add(new Student()); // Student student = new Student(); } Thread.sleep(1000000000L); } } class Student { private byte[] big = new byte[1024*1024]; }
使用jvisualvm点击选择对应的进程,可以看到堆内存占用很高,执行垃圾回收。
内存并没有减少很多。
进行Heap Dump
,选择右侧菜单栏,按照占用内存大小对class进行排序
按照占用内存大小对class进行排序结果如下。
点击类即可看到对应类的所有实例,我们点击占用内存最高的ArrayList
查看实例,点击实例中的elementData
即可查看详情。
发现是可能是student的锅,可以看若干适量实例,确认结论。
再点student对象,定位到属性big。发现一个属性占用了大约1M的空间。这忍不了
然后定位到对应的源码。
/** * 演示查看对象个数 堆转储 dump */ public class Demo1_13 { public static void main(String[] args) throws InterruptedException { List<Student> students = new ArrayList<>(); for (int i = 0; i < 200; i++) { students.add(new Student()); // Student student = new Student(); } Thread.sleep(1000000000L); } } class Student { private byte[] big = new byte[1024*1024]; }
果然,我们有200个Student对象,持有了内存占用1M的big实例200个,并且一直处于生存中。