【JVM】三十三、掌握线上系统 - jmap和jhat带你深入了解对象分布

本文将为大家介绍两个在日常工作中的实用工具:jmap和jhat

1、前文总结

在上一篇文章中,我们向大家介绍了一个在日常工作中的实用工具jstat。通过使用jstat,我们可以非常轻松便捷地了解线上系统的运行状况,包括新对象增速、Young GC触发频率及耗时,以及对象进入老年代的增速和Full GC触发频率及耗时。这些信息有助于我们全面掌握线上系统的JVM运行情况,为可能的优化工作做好准备。

在本文中,我们将继续为大家介绍两个在日常工作中的实用工具:jmap和jhat。这两个工具可以帮助我们观察线上JVM中的对象分布,让我们了解在系统运行过程中,哪些对象占据了主导地位,它们占用了多少内存空间,从而让我们对系统的运行有更加细致的了解。

2、jmap工具带你深入探索运行时的神秘区域

了解JVM的运行状况并进行JVM GC优化时,jstat工具通常已经足够使用。但有时,我们可能会发现JVM中新对象生成的速度非常快,这时我们就可能想要深入了解哪些对象占用了大部分内存。如果发现有些对象的创建时机在代码中可以优化,以避免其对内存的过度占用,那么这甚至可以反过来优化我们的代码。当然,除非出现OOM等极端情况,否则并不急于优化代码。

然而,学习如何了解线上系统JVM中的对象分布仍然是有益的。例如,我们在上周的案例中发现年轻代中总有约500kb的未知对象,大家是否对此感到好奇?如果能看到这500kb的JVM对象到底是什么就好了,因此,学习这个技巧是有用的。

让我们来看一个命令:jmap -heap PID。这个命令可以打印出一系列的信息,但我们不会详细列出所有具体信息,因为内容篇幅过大,而且大部分信息看字面意思就能理解。我们简单说一下这个命令会打印出什么。

大致来说,这个命令会打印出堆内存相关的一些参数设置,以及当前堆内存中各个区域的基本状况,例如Eden区的总容量、已使用容量和剩余空间,两个Survivor区的总容量、已使用容量和剩余空间,以及老年代的总容量、已使用容量和剩余容量。

但是,这些信息大家可能会想,其实jstat已经有了啊!确实如此,所以一般不会用jmap去查看这些信息,毕竟它的信息还没有jstat全面,因为它没有GC相关的统计。

3、使用jmap了解系统运行时的对象分布

jmap命令的一个实用方式如下:

jmap -histo PID

执行该命令后,将会输出类似以下的信息:

78916800_1578303728

这个功能确实非常有趣。请观察上面打印出来的结果,它会根据各个对象所占用的内存空间大小进行降序排列,将占用最多内存的对象置于最顶端。

因此,如果你只是想要简单地了解当前JVM中各个对象对内存的占用情况,只需直接使用jmap -histo命令即可。这个命令非常方便易用。

通过使用该命令,你可以迅速了解到在当前的内存中,到底是哪个对象占用了大量的内存空间,从而有助于你进行进一步的分析和优化。

4、使用jmap生成堆内存转储快照

如果你只是简单地浏览一下,仅仅观察上述对象的内存占用情况,可能会觉得不够深入和细致。为了进行更详细的分析,你可以使用jmap命令生成一个堆内存快照,并将其保存到一个文件中。可以使用以下命令来实现:

jmap -dump:live,format=b,file=dump.hprof PID

这个命令将在当前目录下创建一个名为dump.hprof的文件,该文件以二进制格式保存了JVM堆内存中所有对象的快照。你不能直接打开该文件,因为它是二进制格式的。这个快照可以供你后续进行分析,以便深入了解内存占用情况。

5、使用jhat在浏览器中分析堆转出快照

接下来,我们可以使用jhat工具来分析堆快照。jhat内置了一个web服务器,支持通过浏览器以图形化的方式分析堆转储快照。

使用以下命令启动jhat服务器,并可以指定所需的HTTP端口号(默认为7000):

jhat -port 7000 dump.hprof

然后,在浏览器上访问当前机器的7000端口号,即可通过图形化界面分析堆内存中的对象分布情况。