[alibaba/arthas]使用JVMTI为vmtool工具添加分析占用最大堆内存的类、对象及对象间引用关系的功能

2025-11-12 197 views
4

使用JVMTI在运行时经引用关系遍历堆内对象,统计各个类的实例占用的堆内存、各个对象占用的堆内存,从而得到占用内存最大的若干个类和对象。使用JVMTI遍历对象时所建立的引用关系图,可以回溯特定类的占用内存最大的对象的引用关系,帮助定位对象。同时,对与之相关的文档和在线教程进行补充。

运行命令和效果如下:

$ vmtool -a heapAnalyze --classNum 5 --objectNum 3

class_number: 4101
object_number: 107299

id      #bytes          class_name
----------------------------------------------------
1       209715216       byte[]
2       104857616       byte[]
3       524304          char[]

id      #instances      #bytes          class_name
----------------------------------------------------
1       7043            327124360       byte[]
2       20303           5660096         char[]
3       2936            631136          java.lang.Object[]
4       20270           486480          java.lang.String
5       4110            462904          java.lang.Class

$ vmtool -a referenceAnalyze --className ByteHolder --objectNum 2 --backtraceNum -1

id      #bytes          class_name & references
----------------------------------------------------
1       16              ByteHolder <-- root(local variable in method: main)
2       16              ByteHolder <-- root(local variable in method: sleep)

回答

6

上面输出所使用的测试用例:

class ByteHolder {
    byte[] b;
    ByteHolder(int size) {
        b = new byte[size*1024*1024];
    }
}

public class ByteHolderTest {
    static void sleep() throws Exception {
        ByteHolder bh2 = new ByteHolder(200);
        while (true) {
            Thread.sleep(5000);
        }
    }

    public static void main(String[] args) throws Exception {
        ByteHolder bh1 = new ByteHolder(100);
        sleep();
    }
}
8

@yuankong11 你好,我使用了你的仓库,进行了构建,在mac上很好,但是在Linux上,出现了问题,这个pr是否完整

[arthas@2737702]$ vmtool -a heapAnalyze --classNum 5 --objectNum 3
The value 'heapAnalyze' is not accepted by 'action'
4

您的linux的cpu是不是arm架构的?如果是,arthas目前还不支持。

4

@yuankong11 你好,我使用了你的仓库,进行了构建,在mac上很好,但是在Linux上,出现了问题,这个pr是否完整

[arthas@2737702]$ vmtool -a heapAnalyze --classNum 5 --objectNum 3
The value 'heapAnalyze' is not accepted by 'action'

如果您是使用as-package.sh进行编译后经bin/as.sh启动,那么这个问题可能是因为arthas自动下载了官方的vmtool的lib导致,您可以尝试直接在~/.arthas/lib/3.5.4.*/arthas/中使用java -jar arthas-boot.jar启动arthas,它会引用该目录自行编译下的vmtool lib文件。

8

不是的,x86的。arthas是支持的,vmtool其他命令也支持的。就是他这个pr上的命令不支持,比如

vmtool -a heapAnalyze --classNum 5 --objectNum 3

而在mac上是好的,所以想问下是不是仅支持mac?

8

@yuankong11 你好,我使用了你的仓库,进行了构建,在mac上很好,但是在Linux上,出现了问题,这个pr是否完整

[arthas@2737702]$ vmtool -a heapAnalyze --classNum 5 --objectNum 3
The value 'heapAnalyze' is not accepted by 'action'

如果您是使用as-package.sh进行编译后经bin/as.sh启动,那么这个问题可能是因为arthas自动下载了官方的vmtool的lib导致,您可以尝试直接在~/.arthas/lib/3.5.4.*/arthas/中使用java -jar arthas-boot.jar启动arthas,它会引用该目录自行编译下的vmtool lib文件。

我试过了,还是一样的,mac上是可以的。

7

不是的,x86的。arthas是支持的,vmtool其他命令也支持的。就是他这个pr上的命令不支持,比如

vmtool -a heapAnalyze --classNum 5 --objectNum 3

而在mac上是好的,所以想问下是不是仅支持mac?

我主要的开发平台是WSL1下的Ubuntu 20,mac平台反而是借助github action编译的。另一方面,github action在linux平台上也会执行test部分,是可以通过的,暂时不清楚什么原因。我到完整的linux平台上试验一下,稍后给您回复。

7

不是的,x86的。arthas是支持的,vmtool其他命令也支持的。就是他这个pr上的命令不支持,比如

vmtool -a heapAnalyze --classNum 5 --objectNum 3

而在mac上是好的,所以想问下是不是仅支持mac?

我主要的开发平台是WSL1下的Ubuntu 20,mac平台反而是借助github action编译的。另一方面,github action在linux平台上也会执行test部分,是可以通过的,暂时不清楚什么原因。我到完整的linux平台上试验一下,稍后给您回复。

已经在linux服务器的centos8系统上进行测试,是没有问题的。该问题可能是因为加载了错误的JniLibrary。您可以在arthas-vmtool文件夹中执行mvn test,它应该有如下类似输出,这是test中对heapAnalyze的测试。

class_number: 1275
object_number: 16543

id      #bytes          class_name
----------------------------------------------------
1       51312           byte[]
2       36856           byte[]
3       35136           byte[]
4       31960           byte[]
5       26368           byte[]
...

id      #instances      #bytes          class_name
----------------------------------------------------
1       370             734112          byte[]
2       3236            298880          char[]
3       1284            146040          java.lang.Class
4       3228            77472           java.lang.String
5       1279            40928           java.util.concurrent.ConcurrentHashMap$Node
...
5

不是的,x86的。arthas是支持的,vmtool其他命令也支持的。就是他这个pr上的命令不支持,比如

vmtool -a heapAnalyze --classNum 5 --objectNum 3

而在mac上是好的,所以想问下是不是仅支持mac?

我主要的开发平台是WSL1下的Ubuntu 20,mac平台反而是借助github action编译的。另一方面,github action在linux平台上也会执行test部分,是可以通过的,暂时不清楚什么原因。我到完整的linux平台上试验一下,稍后给您回复。

已经在linux服务器的centos8系统上进行测试,是没有问题的。该问题应该是因为加载了错误的JniLibrary。您可以在arthas-vmtool文件夹中执行mvn test,它应该有如下类似输出,这是test中对heapAnalyze的测试。如果没有,可以检查一下仓库地址是否正确。

class_number: 1275
object_number: 16543

id      #bytes          class_name
----------------------------------------------------
1       51312           byte[]
2       36856           byte[]
3       35136           byte[]
4       31960           byte[]
5       26368           byte[]
...

id      #instances      #bytes          class_name
----------------------------------------------------
1       370             734112          byte[]
2       3236            298880          char[]
3       1284            146040          java.lang.Class
4       3228            77472           java.lang.String
5       1279            40928           java.util.concurrent.ConcurrentHashMap$Node
...

我是ubuntu18,mvn test是有如下输出的,只是使用 java -jar arthas-boot.jar 启动arthas,在执行 vmtool -a heapAnalyze --classNum 5 --objectNum 3的时候有问题

0

我把arthas的进程换成了你的示例程序,可以使用命令,但是错误如下

vmtool -a heapAnalyze --classNum 5 --objectNum 3
vmtool error: arthas.VmTool.heapAnalyze0(II)Ljava/lang/String;

vmtool -a referenceAnalyze --className ByteHolder --objectNum 2 --backtraceNum -1
vmtool error: arthas.VmTool.referenceAnalyze0(Ljava/lang/Class;II)Ljava/lang/String;
8

这是否和JDK的版本有关系

openjdk version "1.8.0_272"
OpenJDK Runtime Environment (build 1.8.0_272-8u272-b10-0ubuntu1~18.04-b10)
OpenJDK 64-Bit Server VM (build 25.272-b10, mixed mode)
8

这是否和JDK的版本有关系

openjdk version "1.8.0_272"
OpenJDK Runtime Environment (build 1.8.0_272-8u272-b10-0ubuntu1~18.04-b10)
OpenJDK 64-Bit Server VM (build 25.272-b10, mixed mode)

我使用open JDK 1.8.0_251并没有复现这一问题,稍后我邮件联系您进一步讨论。

7

跟JDK版本没有关系,JDK里的头文件都放到arthas/arthas-vmtool/src/main/native/head里了。@daxiondi @yuankong11

3

使用智能指针对裸指针进行封装,减少内存管理的负担和内存泄漏的可能性。

2

heapAnalyze的功能和jmap histo比较重合;referenceAnalyze只是分析有某个类对象的引用,并不会对引用的数量、占用的字节数进行排序,这个有可能根据引用数量倒排序吗?

6

heapAnalyze的功能和jmap histo比较重合;referenceAnalyze只是分析有某个类对象的引用,并不会对引用的数量、占用的字节数进行排序,这个有可能根据引用数量倒排序吗?

@fan0916 heapAnalyze跟histo功能比较重合,只是实现方式不同,这里基于JVMTI的方式。referenceAnalyze最初引入的目的是使用heapAnalyze后能够帮助定位到占用大内存的对象的来源,并不会进行排序,但是这部分功能是可以实现的,只需要建立完整的引用关系图,在图上进行统计就行。

0

heapAnalyze的功能和jmap histo比较重合;referenceAnalyze只是分析有某个类对象的引用,并不会对引用的数量、占用的字节数进行排序,这个有可能根据引用数量倒排序吗?

@fan0916 heapAnalyze跟histo功能比较重合,只是实现方式不同,这里基于JVMTI的方式。referenceAnalyze最初引入的目的是使用heapAnalyze后能够帮助定位到占用大内存的对象的来源,并不会进行排序,但是这部分功能是可以实现的,只需要建立完整的引用关系图,在图上进行统计就行。

使用JVMTI实现histo相对有下面两个好处:1)有高度灵活的可定制性,可以实现如引用关系分析的功能。 2)jmap的histo功能基于迭代堆内对象实现,这里基于引用关系遍历实现,不能由GC root可达的对象事实上不太需要关心。

5

$ vmtool -a heapAnalyze --classNum 5 --objectNum 3 The value 'heapAnalyze' is not accepted by 'action' 为啥我的arthas中没有这个命令参数,需要怎么引用,谢谢!

3

$ vmtool -a heapAnalyze --classNum 5 --objectNum 3 The value 'heapAnalyze' is not accepted by 'action' 为啥我的arthas中没有这个命令参数,需要怎么引用,谢谢!

这个PR还没有合并到主分支,您可以参考这个fork(https://github.com/yuankong11/arthas)编译使用