使用JDK的ServiceAbility获得特定的对象

本文介绍如何利用JDK自带的ServiceabilityAgent工具,通过编写JS脚本来查找Java程序中元素数量异常的HashSet实例。文章详细展示了从创建测试程序到使用ServiceabilityAgent的GUI界面及JS命令行工具进行查询的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

遇到这样一个问题: Java程序中有很多个HashSet. 想找到其元素数目不正常的HashSet的实例. 

当然这个可以用各种工具来做(比如JProfiler等等).

这里用的是JDK自带的ServiceAbility Agent.

具体介绍可以参见

http://rednaxelafx.iteye.com/blog/1847971


首先写个简单的测试程序:


   HashSet s = new HashSet<>();
        for (int i=0; i<100; i++) {
            s.add(i);
        }
        Thread.sleep(100000000);

运行, 使用JPS找到java进程的pid, 然后进入SA的GUI界面:


java -cp .:$JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB


然后,进入Tools - Find Object by Query, 输入查询语句

select a from java.util.HashSet a

和SQL很像吧.


这时列出了JDK中当前的所有HashSet的实例的地址. 随便点一个, 查看其内容:


正好就是size = 100的. 然后, 点开其中的tables, 就可以看到key是什么了.

至于为什么属性的顺序是map -> table, 原因就是HashSet其实是个HashMap来实现的.



OK, 那么问题来了: 在真正的产品中, 不可能像这个小测试程序一样, 只有这么几个HashSet. 那么, 如何找到目标HashSet呢?

有两种方法: 

1. 上面的Find Object by Query, 是可以些where条件的, 但是我没有试验出来

2. 使用下面介绍的方法,就是使用Serviceability Agent的JS命令行工具.

在SA的JS命令行工具中, 提供了各种预定义的JS封装的工具类和工具函数, 可以查询JDK内部的各种信息. 感兴趣的可以查看sa-jdi.jar中的sun\jvm\hotspot\utilities\soql\sa.js


首先运行JS工具,连接到Java进程.这里同样用到了pid

C:\jdk8>java -cp .;./lib/sa-jdi.jar sun.jvm.hotspot.tools.soql.JSDB 7540
Attaching to process ID 7540, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
jsdb>


然后编辑如下的.js脚本:

print("loaded");
var oh = sa.vm.getObjectHeap();
var kls = findInstanceKlass("java.util.HashSet");
print("kls = " + kls);

forEachOopOfKlass(function(a){
	 // print(a.getHandle());
	 var o = object(addr2str(a.handle));
	 print("Size = " + o.map.size);
	 if (o.map.size >= 100) {
		 print("A set with at least 100 objs", a.handle);
	 }
}, kls, false)


为了方便, 可以在编辑器中编辑, 然后在jsdb中load这个脚本,比如

jsdb> load("c:\\dev\\a.js");


OK, 其实也比较简单. 首先找到类的定义的地址, 然后根据这个地址for each每个类的实例.

对于每个类的实例, 回调处理函数function(a) . 在这个回调函数中, 参数a就是每个实例的表示对象.

a.handle, 就是JDK内部a的地址 (和上面截图中SOQL查询出来的地址一致). 

关键在于

var o = object(addr2str(a.handle));
这一行. 

这一行根据sa.js内置的函数,将地址转换成字符串, 最后通过函数object, 得到具体的类的实例.

最后根据o.map.size >= 100, 就可以打印出来要查找的地址了.


最后, 得到查找的地址之后,可以在SA GUI工具的Tools - Inspect 中直接观察这个地址, 和之前在GUI工具中几个地址一个一个试验, 结果是一致的.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值