前几天分享了一下基于Attach API实现一个jstack功能的demo, 于是有圈友私下问我,什么是SA?如果基于SA如何实现jstack?
本篇片呢就介绍下SA,以及使用SA来开发一个统计JVM堆里对象的工具。
简介
SA全称Serviceability Agent,它是hotspot虚拟机开发人员,为了调试虚拟机而开发的一个组件。它是利用操作系统底层API来读取一个进程的数据。
它与Attach API最大的不同是:attach通过连接到目标JVM进程,让目标JVM进程执行相关命令来实现;而sa是独立于目标JVM进程运行。
之前我们介绍的HSDB就是基于SA来实现的。SA只能支持读取一个进程的快照信息,换句话说,当采用SA连接到目标进程时,目标进程会暂停住,直到断开连接后目标进程才会继续运行。所以切勿在线上环境使用基于SA的工具。
对象统计工具
有了以上对SA的了解,接下来就看看如何基于SA开发一个统计对象的工具。
jdk通过sa-jdi.jar提供了相关的工具类,我们可以基于这些类很简单的实现这个功能。直接上代码:
public class TestSA extends Tool { @Override public void run() { Map<Klass,Value> map = new HashMap<>(); ObjectHeap objectHeap = VM.getVM().getObjectHeap(); objectHeap.iterate(new HeapVisitor() {//遍历堆里的对象 @Override public void prologue(long l) { } @Override public boolean doObj(Oop oop) { Klass klass = oop.getKlass();//获取对象的class Value value = map.get(klass); if(value == null){ value = new Value(); map.put(klass,value); } value.increase();//对象数目加一 value.add(oop.getObjectSize());//对象大小 return false; } @Override public void epilogue() { } }); for(Map.Entry<Klass,Value> entry:map.entrySet()){ StringBuilder sb = new StringBuilder("name:"); sb.append(entry.getKey().getName().asString()) .append("---count:").append(entry.getValue().getCount()) .append("---size:").append(entry.getValue().getSize()); System.out.println(sb.toString()); } } private class Value{ private int count = 0; private long size = 0; public void increase(){ count++; } public void add(long size){ this.size+=size; } public int getCount(){ return count; } public long getSize(){ return size; } } public static void main(String[] args) { TestSA testSA = new TestSA(); testSA.execute(args); } }
我们只需要继承Tool类(一定是sun.jvm.hotspot.tools.Tool哦),然后重写run方法,在run方法里调用相关api来获取数据。
运行这个类时,记得要用管理员权限哦,还要指定要统计的jvm进程的pid。如下是我运行这个类的命令:
sudo java -cp .:$JAVA_HOME/lib/sa-jdi.jar sa.TestSA 1288
还需要强调的是,这个命令要在sa.TestSA类所在的目录下运行,否则会报找不到TestSA的错误。
作者:_清泉_
链接:https://www.jianshu.com/p/a906dbf3cbed