内存可视化工具之HSDB大揭秘,看完可以出去吹牛逼了!

本文内容过于硬核,建议有 Java 相关经验人士阅读。

HSDB(Hotspot Debugger) 是 JDK 自带的工具,用于查看 JVM 运行时的状态。

使用方式由于在 JDK 9 之前没有正式提供,所以也未在 JDK 的 bin 目录下提供直接可执行文件,需要在命令行执行命令才能启动。

首先在命令行中先 cd 至 C:\Program Files\Java\jdk1.8.0_221\lib 黑色目录,然后执行:

< pre class=“hljs css” style=“padding: 0.5em; font-family: Menlo,
Monaco, Consolas, “Courier New”, monospace; color: rgb(68, 68, 68);
border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size:
14px; line-height: 1.5em; word-break: break-all; overflow-wrap:
break-word; white-space: pre; background-color: rgb(246, 246, 246);
border: none; overflow-x: auto; font-style: normal;
font-variant-ligatures: normal; font-variant-caps: normal;
font-weight: 400; letter-spacing: normal; orphans: 2; text-align:
start; text-indent: 0px; text-transform: none; widows: 2;
word-spacing: 0px; -webkit-text-stroke-width: 0px;
text-decoration-style: initial; text-decoration-color: initial;”>java
-cp .\sa-jdi.jar sun.jvm.hotspot.HSDB< /pre>

我在执行这句命令的时候报了个错:

< pre class=“prettyprint hljs sql” style=“padding: 0.5em; font-family:
Menlo, Monaco, Consolas, “Courier New”, monospace; color: rgb(68, 68,
68); border-radius: 4px; display: block; margin: 0px 0px 1.5em;
font-size: 14px; line-height: 1.5em; word-break: break-all;
overflow-wrap: break-word; white-space: pre; background-color:
rgb(246, 246, 246); border: none; overflow-x: auto; font-style:
normal; font-variant-ligatures: normal; font-variant-caps: normal;
font-weight: 400; letter-spacing: normal; orphans: 2; text-align:
start; text-indent: 0px; text-transform: none; widows: 2;
word-spacing: 0px; -webkit-text-stroke-width: 0px;
text-decoration-style: initial; text-decoration-color:
initial;”>Exception in thread “Thread-1”
java.lang.UnsatisfiedLinkError: Can’t load library: C:\Program
Files\Java\jdk-11.0.4\bin\sawindbg.dll at
java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2620) at
java.base/java.lang.Runtime.load0(Runtime.java:767) at
java.base/java.lang.System.load(System.java:1831) at
sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.(WindbgDebuggerLocal.java:661)
at
sun.jvm.hotspot.HotSpotAgent.setupDebuggerWin32(HotSpotAgent.java:567)
at sun.jvm.hotspot.HotSpotAgent.setupDebugger(HotSpotAgent.java:335)
at sun.jvm.hotspot.HotSpotAgent.go(HotSpotAgent.java:304) at
sun.jvm.hotspot.HotSpotAgent.attach(HotSpotAgent.java:140) at
sun.jvm.hotspot.HSDB.attach(HSDB.java:1184) at
sun.jvm.hotspot.HSDB.access25MainLoop.run(WorkerThread.java:66) at
java.base/java.lang.Thread.run(Thread.java:834)< /pre>

含义是有一个 sawindbg.dll 黑色在 jdk 的目录下找不到,因为我本地有多个 jdk ,配置环境变量的是 jdk 11 ,我在 jdk 8 的 jre 的 bin 目录下找到了这个文件,直接 copy 到 jdk 11 的bin 目录下解决此问题。

执行完成后会打开这么个界面:
             内存可视化工具之HSDB大揭秘,看完可以出去吹牛逼了!_第1张图片
接下来,我们写一小段测试代码:

public abstract class A {
     
public void printMe() {
     
System.out.println("I am A class");
}
public abstract void sayHello();
}

public class B extends A {
     
@Override
public void sayHello() {
     
System.out.println("I am B class");
}
}

public class HSDB_Test {
     
public static void main(String[] args) throws IOException {
     
A obj = new B();
// 无意义,单纯用作卡住主线程,防止线程结束
System.in.read();
System.out.println(obj);
}
}

首先在命令行中使用命令 jps -l 查看 Java 进程的 pid :

<pre class="prettyprint hljs vim" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">PS C:\Users\inwsy> jps -l
1648 com.geekdigging.lesson04.jvmtools.HSDB_Test
8704
9280 org.jetbrains.jps.cmdline.Launcher
14724 jdk.jcmd/sun.tools.jps.Jps
3220 org/netbeans/Main
15144
20572 org.jetbrains.jps.cmdline.Launcher
7548 sun.jvm.hotspot.HSDB</pre>

可以看到,我们刚写的测试方法的 pid 是 1648 ,在 HSDB 中点击 File > Attach to Hotspot process :
内存可视化工具之HSDB大揭秘,看完可以出去吹牛逼了!_第2张图片
第一个看到的就是当前进程中的线程:
内存可视化工具之HSDB大揭秘,看完可以出去吹牛逼了!_第3张图片
到这里,我们的准备工作就已经结束,接着我们使用 Tools > Class Browser 找到对象 B 的内存地址:
内存可视化工具之HSDB大揭秘,看完可以出去吹牛逼了!_第4张图片
图中红框框起来的是我自己写的三个类,可以看到我这里 B 的内存地址是 0x00000007c0060c18 。

接下来,使用 Tools > Inspector 查看这个对象的详细信息:
内存可视化工具之HSDB大揭秘,看完可以出去吹牛逼了!_第5张图片
vtable 是虚表方法,这里我们看到 class B 有 7 个虚表方法,因为所有的对象都继承自 Object ,所以 B 继承了 Object 的 5 个方法,然后还继承了 A 的一个方法,自己重写了一个方法,总共是 7 个方法。

这个我们可以进行一下验证,可以在 Windows > Console 中使用 mem 命令进行查看。

那么我们可以开始计算, vtable 是在 instanceKlass 对象实例的尾部,而 instanceKlass 大小在 64 位系统的大小为 0x1B8 ,因此 vtable 的起始地址等于 instanceKlass 的内存首地址加上 0x1B8 等于 7C0060DD0 。
内存可视化工具之HSDB大揭秘,看完可以出去吹牛逼了!_第6张图片
接下来,我们在 Windows > Console 中使用 mem 命令进行验证:
内存可视化工具之HSDB大揭秘,看完可以出去吹牛逼了!_第7张图片
第一列是方法实际在堆中的内存地址,第二列则是内存指针地址,我们可以将拿到的内存指针地址去 A , B 和 Object 中分别查看,可以看到前 5 行对应的是 Object 的方法,第 6 行对应的是 A 对象中的方法,第 7 行则对应 B 对象中的方法。

你可能感兴趣的:(java,jdk,jvm)