jmap命令的实现原理解析

作者: 美团Java | 来源:发表于2017-12-16 15:39 被阅读1477次

    简书 占小狼,转载请注明原创出处,谢谢!

    当服务发生GC问题时,一般会使用jmap工具进行分析,jmap工具很强大,所以有必要了解它的方方面面。

    jmap可以做什么?

    1、jmap -histo[:live] <pid>

    通过histo选项,打印当前java堆中各个对象的数量、大小。
    如果添加了live,只会打印活跃的对象。

    2、jmap -dump:[live,]format=b,file=<filename> <pid>

    通过-dump选项,把java堆中的对象dump到本地文件,然后使用MAT进行分析。
    如果添加了live,只会dump活跃的对象。

    3、jmap -heap <pid>

    通过-heap选项,打印java堆的配置情况和使用情况,还有使用的GC算法。

    4、jmap -finalizerinfo <pid>

    通过-finalizerinfo选项,打印那些正在等待执行finalize方法的对象。

    5、jmap -permstat <pid>

    通过-permstat选项,打印java堆永久代的信息,包括class loader相关的信息,和interned Strings的信息。

    jmap实现原理

    通过jmap和jvm之间进行通信,有两种实现方式:attach 和 SA。

    attach

    attach方式,简单来说就是客户端和服务端之间的通信,客户端发送请求,主要逻辑在服务端执行,jmap相当于客户端,JVM相当于服务端。

    在JVM中,有一个叫"Attach Listener"的线程,专门负责监听attach的请求,并执行对应的操作。

    比如现在执行"jmap -histo:live 5409",一步一步的实现如下:
    1、在Jmap.java类的main函数中,对参数进行解析。
    2、解析出来参数中有“-histo:live”,则执行histo方法:

    attach方法建立了jmap进程和JVM之间的socket连接,建立过程可以查看笨神的文章JVM Attach机制实现,后续基于该连接进行通信。

    因为命令行中添加了[:live]选项,这里的live参数是true。

    再看看heapHisto方法

    executeCommand方法基于之前的socket连接向JVM发送了一条"inspectheap"命令,当然了,还有参数。

    虚拟机的"Attach Listener"线程当发现有新的命令时,就拿出来处理它。

    命令和具体的函数对应关系如下:

    和"inspectheap"对应的是heap_inspection方法,实现如下:

    live_objects_only的值取决于请求中是否有"-live",再jmap中,取决于是否有":live",所以不管是不是添加了":live",都会有STW过程,时间长短而已。

    在VM_GC_HeapInspection的doit方法中

    _full_gc的值就是live_objects_only,如果为true,可能会执行一次full gc,清空非活跃的对象,但是可能会因为GC locker,导致跳过本次的GC。

    "jmap -dump"实现的原理和"jmap -histo"类似,都是通过attach的方式实现,
    attach API的实现方式是:
    1、客户端连接到目标JVM,向其发出一个类似“inspectheap”命令;
    2、目标JVM接收到命令,执行JVM内相关函数,将收集到的结果以文本形式返回;
    3、客户端接收到返回的文本并将其显示出来;

    SA

    假如执行"jmap -heap 5409",就不会使用attach方式实现了。

    在参数解析中,如果参数是"-heap|-heap:format=b|-permstat|-finalizerinfo"中的一种,或者添加了"-F",比如"jmap -histo -F 5409",则使用SA的方式。

    SA方式,和attach方式不同的是,相关的主要逻辑都在SA中实现,从JVM中获取数据即可。

    可以大概看下"jmap -heap"的实现,对应的实现类是"HeapSummary",内部通过BugSpotAgent工具类attach到目标VM,更具体的底层细节,可以参考HotSpot Serviceability Agent 实现浅析

    执行jmap -heap有些时候可能会导致进程变T,一般是有一个线程在等信号量,这时会block住其它所有线程,可以执行kill -CONT <pid>进行恢复,不过还是强烈建议别执行这个命令。

    相关文章

      网友评论

      • 巨子联盟:请教个问题,你最后说 "执行jmap -heap有些时候可能会导致进程变T" 变T是啥意思呢?

      本文标题:jmap命令的实现原理解析

      本文链接:https://www.haomeiwen.com/subject/jhyswxtx.html