当前位置: 首页 > news >正文

JVM深入研究--JHSDB (jvm 分析工具)

文章目录

    • 前言
    • A.java
    • A.class
    • javap 反编译 class
    • JHSDB (java hotspot debug)
    • 查看类信息
    • A() 构造方法
    • main() 方法
    • rap() 方法
    • 常量池
    • 对象内存信息
    • 虚拟机栈

当你迷茫的时候,请点击JVM 目录大纲 快速查看前面的技术文章,相信你总能找到前行的方向

前言

上一篇 JVM 深入研究 – 详解class 文件 结合官网文档分析 class 文件示例,作为 JVM 深入学习的开篇,今天来通过工具来简化分析 class 的步骤

A.java

先上原代码,回顾一下故事的主角:

package basic.object;public class A {// 一段rapprivate String song = "你看这个面它又长又宽,还有这个碗它又大又圆,两者之间并没有关系,但我要用rap把它们缝在一起,耶!";public void rap() {System.out.println(this.song);}public static void main(String[] args) throws Exception {A obj = new A();obj.rap();obj.getClass();while (true){}}
}

A.class

执行javac A.java 原码编译后形成 A.class 文件,是一堆十六进制的字节码,通过上节分析,展示一下它的区块全貌:

在这里插入图片描述
分析一下前16个字节含义:CAFEBABE 0000 0034 0034 0A 000A 0020 08

  1. 前 4 字节:CA FE BA BE(魔数)
    这是 Java class 文件的标志性开头,称为 “魔数”(Magic Number)
    作用:用于 JVM 快速识别是否为有效的 class 文件
    十六进制 “CAFEBABE” 对应英文 “咖啡宝贝”,是 Java 语言的标志性设计

  2. 接下来 4 字节:0000 0034(版本号)
    前 2 字节(0000):minor_version(次版本号)= 0
    后 2 字节(0034):major_version(主版本号)= 52(十六进制 34 转换为十进制是 52)
    版本对应关系:Java 8 的主版本号是 52,因此这个 class 文件是由 Java 8 编译产生的

  3. 接下来 2 字节:0034(常量池长度)
    表示常量池中有 52 项(34 十六进制 = 52 十进制)
    注意:常量池索引从 1 开始,因此实际有效索引范围是 1~52,共 52 项

  4. 剩余 6 字节:0A 00 0A 00 20 08(常量池前 3 项)
    class 文件在版本号和常量池长度之后,就是常量池的具体内容,每一项都是一个常量:
    第 1 字节(0A):表示常量池第 1 项的类型是 CONSTANT_Methodref_info(方法引用)

    接下来 2 字节(000A):指向声明方法的类的索引,对应常量池第 10 项

    接下来 2 字节(0020):指向方法名称和描述符的索引,对应常量池第 32 项

    第 6 字节(08):表示常量池第 2 项的类型是 CONSTANT_String_info(字符串常量)

javap 反编译 class

javap 命令查看字节码 javap -v A.class

  Classfile /path/to/java-oops/target/classes/basic/object/A.classLast modified 2025-9-26; size 969 bytesMD5 checksum 7b641ea8aee513d0afbf8492ea0fd19eCompiled from "A.java"
public class basic.object.Aminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #10.#32        // java/lang/Object."<init>":()V#2 = String             #33            // 你看这个面它又长又宽,还有这个碗它又大又圆,两者之间并没有关系,但我要用rap把它们缝在一起,耶!#3 = Fieldref           #6.#34         // basic/object/A.song:Ljava/lang/String;#4 = Fieldref           #35.#36        // java/lang/System.out:Ljava/io/PrintStream;#5 = Methodref          #37.#38        // java/io/PrintStream.println:(Ljava/lang/String;)V#6 = Class              #39            // basic/object/A#7 = Methodref          #6.#32         // basic/object/A."<init>":()V#8 = Methodref          #6.#40         // basic/object/A.rap:()V#9 = Methodref          #10.#41        // java/lang/Object.getClass:()Ljava/lang/Class;#10 = Class              #42            // java/lang/Object#11 = Utf8               song#12 = Utf8               Ljava/lang/String;#13 = Utf8               <init>#14 = Utf8               ()V#15 = Utf8               Code#16 = Utf8               LineNumberTable#17 = Utf8               LocalVariableTable#18 = Utf8               this#19 = Utf8               Lbasic/object/A;#20 = Utf8               rap#21 = Utf8               main#22 = Utf8               ([Ljava/lang/String;)V#23 = Utf8               args#24 = Utf8               [Ljava/lang/String;#25 = Utf8               obj#26 = Utf8               StackMapTable#27 = Class              #39            // basic/object/A#28 = Utf8               Exceptions#29 = Class              #43            // java/lang/Exception#30 = Utf8               SourceFile#31 = Utf8               A.java#32 = NameAndType        #13:#14        // "<init>":()V#33 = Utf8               你看这个面它又长又宽,还有这个碗它又大又圆,两者之间并没有关系,但我要用rap把它们缝在一起,耶!#34 = NameAndType        #11:#12        // song:Ljava/lang/String;#35 = Class              #44            // java/lang/System#36 = NameAndType        #45:#46        // out:Ljava/io/PrintStream;#37 = Class              #47            // java/io/PrintStream#38 = NameAndType        #48:#49        // println:(Ljava/lang/String;)V#39 = Utf8               basic/object/A#40 = NameAndType        #20:#14        // rap:()V#41 = NameAndType        #50:#51        // getClass:()Ljava/lang/Class;#42 = Utf8               java/lang/Object#43 = Utf8               java/lang/Exception#44 = Utf8               java/lang/System#45 = Utf8               out#46 = Utf8               Ljava/io/PrintStream;#47 = Utf8               java/io/PrintStream#48 = Utf8               println#49 = Utf8               (Ljava/lang/String;)V#50 = Utf8               getClass#51 = Utf8               ()Ljava/lang/Class;
{private java.lang.String song;descriptor: Ljava/lang/String;flags: ACC_PRIVATEpublic basic.object.A();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: aload_05: ldc           #2                  // String 你看这个面它又长又宽,还有这个碗它又大又圆,两者之间并没有关系,但我要用rap把它们缝在一起,耶!7: putfield      #3                  // Field song:Ljava/lang/String;10: returnLineNumberTable:line 3: 0line 6: 4LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   Lbasic/object/A;public void rap();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;3: aload_04: getfield      #3                  // Field song:Ljava/lang/String;7: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V10: returnLineNumberTable:line 9: 0line 10: 10LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   Lbasic/object/A;public static void main(java.lang.String[]) throws java.lang.Exception;descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new           #6                  // class basic/object/A3: dup4: invokespecial #7                  // Method "<init>":()V7: astore_18: aload_19: invokevirtual #8                  // Method rap:()V12: aload_113: invokevirtual #9                  // Method java/lang/Object.getClass:()Ljava/lang/Class;16: pop17: goto          17LineNumberTable:line 13: 0line 14: 8line 15: 12line 16: 17LocalVariableTable:Start  Length  Slot  Name   Signature0      20     0  args   [Ljava/lang/String;8      12     1   obj   Lbasic/object/A;StackMapTable: number_of_entries = 1frame_type = 252 /* append */offset_delta = 17locals = [ class basic/object/A ]Exceptions:throws java.lang.Exception
}
SourceFile: "A.java"

JHSDB (java hotspot debug)

JHSDB (java hotspot debug),是一个功能非常强大的 Java 故障诊断和性能分析工具,要注意的是,程序与hsdb 要在同一版本的jdk环境中运行,而在 jdk8 没有 hsdb 工具,我电脑上安装了 openjdk 11,17,21 都有hsdb工具,本文这用的是 openjdk21 环境,终端执行 jhsdb hsdb 命令打开hsdb 页面,执行jps 查看pid,再连接上进程。

File -> Attach to HotSpot process

Tools 中有很多实用的工具

Class Browser

查看类信息

public class basic.object.A @0x000000c801003000
在这里插入图片描述
主要维护有父类指针(Super Class),属性(Fields),方法(Methods),常量池指针(Constant Pool)

  • Super Class

public class java.lang.Object @0x000000c800000e70

  • Fields
    private java.lang.String song; (offset = 12)

  • Methods

    1. public void <init>() @0x0000000130408ca8;
    2. public static void main(java.lang.String[]) @0x0000000130408e28;
    3. public void rap() @0x0000000130408d58;
  • Constant Pool
    Constant Pool of [public class basic.object.A @0x000000c801003000] @0x0000000130408a10

Class Hierarchy of public class basic.object.A @0x000000c801003000

public class basic.object.A @0x000000c801003000public class java.lang.Object @0x000000c800000e70

A() 构造方法

public void \<init\>() @0x0000000130408ca8

Bytecode:

 0 aload_01 invokespecial #1 <java/lang/Object.<init> : ()V>4 aload_05 ldc #2 <你看这个面它又长又宽,还有这个碗它又大又圆,两者之间并没有关系,但我要用rap把它们缝在一起,耶!>7 putfield #3 <basic/object/A.song : Ljava/lang/String;>
10 return

main() 方法

public static void main(java.lang.String[]) @0x0000000130408e28

Checked Exception(s) :

public class java.lang.Exception @0x000000c80000bf58

Bytecode

 0 new #6 <basic/object/A>3 dup4 invokespecial #7 <basic/object/A.<init> : ()V>7 astore_18 aload_19 invokevirtual #8 <basic/object/A.rap : ()V>
12 aload_1
13 invokevirtual #9 <java/lang/Object.getClass : ()Ljava/lang/Class;>
16 pop
17 goto 17 (0)

rap() 方法

public void rap() @0x0000000130408d58

Bytecode

 0 getstatic #4 <java/lang/System.out : Ljava/io/PrintStream;>3 aload_04 getfield #3 <basic/object/A.song : Ljava/lang/String;>7 invokevirtual #5 <java/io/PrintStream.println : (Ljava/lang/String;)V>
10 return

常量池

常量池存储情况:

常量池完整信息

IndexConstant TypeConstant Value
1JVM_CONSTANT_Methodref#10 #32
2JVM_CONSTANT_String“你看这个面它又长又宽,还有这个碗它又大又圆,两者之间并没有关系,但我要用rap把它们缝在一起,耶!”
3JVM_CONSTANT_Fieldref#6 #34
4JVM_CONSTANT_Fieldref#35 #36
5JVM_CONSTANT_Methodref#37 #38
6JVM_CONSTANT_Classpublic class basic.object.A @0x000000c801003000 (klass=0x000000c801003000)
7JVM_CONSTANT_Methodref#6 #32
8JVM_CONSTANT_Methodref#6 #40
9JVM_CONSTANT_Methodref#10 #41
10JVM_CONSTANT_Classpublic class java.lang.Object @0x000000c800000e70 (klass=0x000000c800000e70)
11JVM_CONSTANT_Utf8“song”
12JVM_CONSTANT_Utf8“Ljava/lang/String;”
13JVM_CONSTANT_Utf8“<init>”
14JVM_CONSTANT_Utf8“()V”
15JVM_CONSTANT_Utf8“Code”
16JVM_CONSTANT_Utf8“LineNumberTable”
17JVM_CONSTANT_Utf8“LocalVariableTable”
18JVM_CONSTANT_Utf8“this”
19JVM_CONSTANT_Utf8“Lbasic/object/A;”
20JVM_CONSTANT_Utf8“rap”
21JVM_CONSTANT_Utf8“main”
22JVM_CONSTANT_Utf8“([Ljava/lang/String;)V”
23JVM_CONSTANT_Utf8“args”
24JVM_CONSTANT_Utf8“[Ljava/lang/String;”
25JVM_CONSTANT_Utf8“obj”
26JVM_CONSTANT_Utf8“StackMapTable”
27JVM_CONSTANT_UnresolvedClassbasic/object/A
28JVM_CONSTANT_Utf8“Exceptions”
29JVM_CONSTANT_Classpublic class java.lang.Exception @0x000000c80000bf58 (klass=0x000000c80000bf58)
30JVM_CONSTANT_Utf8“SourceFile”
31JVM_CONSTANT_Utf8“A.java”
32JVM_CONSTANT_NameAndType#13 #14
33JVM_CONSTANT_Utf8“你看这个面它又长又宽,还有这个碗它又大又圆,两者之间并没有关系,但我要用rap把它们缝在一起,耶!”
34JVM_CONSTANT_NameAndType#11 #12
35JVM_CONSTANT_Classpublic final class java.lang.System @0x000000c800002bf8(klass=0x000000c800002bf8)
36JVM_CONSTANT_NameAndType#45 #46
37JVM_CONSTANT_Classpublic class java.io.PrintStream @0x000000c80000a360 (klass=0x000000c80000a360)
38JVM_CONSTANT_NameAndType#48 #49
39JVM_CONSTANT_Utf8“basic/object/A”
40JVM_CONSTANT_NameAndType#20 #14
41JVM_CONSTANT_NameAndType#50 #51
42JVM_CONSTANT_Utf8“java/lang/Object”
43JVM_CONSTANT_Utf8“java/lang/Exception”
44JVM_CONSTANT_Utf8“java/lang/System”
45JVM_CONSTANT_Utf8“out”
46JVM_CONSTANT_Utf8“Ljava/io/PrintStream;”
47JVM_CONSTANT_Utf8“java/io/PrintStream”
48JVM_CONSTANT_Utf8“println”
49JVM_CONSTANT_Utf8“(Ljava/lang/String;)V”
50JVM_CONSTANT_Utf8“getClass”
51JVM_CONSTANT_Utf8“()Ljava/lang/Class;”

对象内存信息

Object Histogram -> Inspect

虚拟机栈

这里把程序变一下,来查看虚拟机栈的信息情况

    public static void main(String[] args) throws Exception {A obj = new A();while (true) {obj.rap();obj.getClass();}}

hsdb 查看main线程栈信息

上图可以看出,虚拟机栈其实存的都是方法帧

栈底是 main() -> 接着是rap() -> 接着是 println() -> writeln -> … ->java.io.FileOutputStream.write(byte[], int, int) -> 栈顶为 private native void writeBytes(byte[], int, int, boolean)

最终调到的是本地方法栈中的 native void writeBytes 方法。

对应栈内存里面也可以看出:

http://www.dtcms.com/a/427558.html

相关文章:

  • AI的局限性,有所能与有所不能
  • 广州网站设计公司推荐哪家网站的风格设计有哪些
  • 【完整源码+数据集+部署教程】武装人员图像分割系统: yolov8-seg-GFPN
  • 开发避坑指南(61):Redis持久化失败:RDB快照因磁盘问题无法保存解决方案
  • 短视频网站如何做推广网站导航栏最多可以做几个
  • 做自由行的网站广告运营推广
  • 逆向爬虫——JavaScript混淆技术
  • 4.0 Labview中算法实例1-迟滞曲线上两段的平均差(拐点计算)
  • 网站建设数据库搭建西安广告设计制作公司
  • 作一手房用什么做网站有关学校网站建设策划书
  • 企业网站建设方案详细方案厦门网站建设2
  • 微服务服务治理
  • 网站定制费用银川建设网站
  • [陇剑杯 2021]简单日志分析(问3)
  • 微信的网站徐州网站设计师
  • CC工具箱使用指南:【整库修复几何】
  • 【完整源码+数据集+部署教程】工厂工人操作机械工作图像分割系统: yolov8-seg-RepHGNetV2
  • 网站设计与制作简单吗可以用来注册网站域名的入口是
  • 怎样做内网网站seo企业网络推广培训
  • C 语言各种指针详解
  • 【个人随想】我们是否缺乏从头再来的勇气
  • 自监督学习在医疗AI中的技术实现路径分析(上)
  • 麻涌手机网站设计建设的网站服务器
  • 五维论-解释万物法则
  • 国际海运业务全流程操作解析:易境通海运系统如何赋能各环节?
  • 【代码随想录day 29】 力扣 406.根据身高重建队列
  • 上海网站建设报价单网站设计平台及开发工具
  • 2006 年真题配套词汇单词笔记(考研真相)
  • Ubuntu 24.04 安装搜狗输入法完整教程
  • 淘宝买cdk自己做网站游戏编程软件