JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用

简介: 这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。

前言

  1. 文中所用到的class文件结构思维导图下载:class文件思维导图(这个思维导图的来源是下面 的 jvm class 文件格式 官网
  2. jvm 13版本 规范 HTML 版本:https://docs.oracle.com/javase/specs/jvms/se19/html/index.html
  3. java 各版本和 JVM各版本下载:https://docs.oracle.com/javase/specs/index.html
  4. 本博文是以jdk8版本学习的,文档是13版本。
  5. 本博客是讲:
    • JVM的一些基础、跨平台的语言和跨语言的平台。
    • 字节码 Class 文件(Class File Format) 的十六进制的布局、含义,看class文件的几个工具。
  6. 下个博文讲,class文件如何加载(load)到内存以及加载的。
  7. 知识体系分布:
    1. JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
    2. JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
    3. JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
    4. JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配

一、JVM基础

1、cross platform 跨平台

即任何语言只要编译成 class 文件,在装有JVM任何的系统上 都可以运行。

在这里插入图片描述

2、cross language 跨语言

即:有好多语言是在JVM上运行的,这就是夸语言的。
在这里插入图片描述

3、什么是JVM呢?一张图告诉你

在这里插入图片描述

4、java从编码到执行*****

  1. 通过 javac 命令:将 java文件 编译成 class 文件
  2. 通过 java 命令:classloader 加载 class 文件以及 java 类库 到内存中进行装载,装载完成后, 然后调用 字节码解释器 或者JIT即时编译器 来进行解释 或者 编译。
  3. 之后 由 执行引擎 进行 执行,最终到OS操作系统。
  • 那java是解释执行的还是编译执行的呢?其实 解释和编译是可以混合的,如果代码用到的次数比较多,会把代码做成 即时编译 即做成本地的编译,就类似c语言在win中编译成exe文件,这样效率会比较高。
    在这里插入图片描述

5. 从跨平台的语言到跨语言的平台

JVM:是跨语言的平台。
java:是跨平台的语言。
在JVM上能够跑的语言 到目前有100多种,比如下图中的Scala、groovy语言等。
在这里插入图片描述

6. jvm与class文件格式

== jvm跟java无关==
在这里插入图片描述

7. JVM

  • jvm是一种规范 – java virtual machine specifications
    • https://docs.oracle.com/en/java/javase/13/
    • https://docs.oracle.com/javase/specs/index.html
  • JVM 是 虚构出来的一台计算机
    • 字节码指令集(汇编语言)
    • 内存管理:栈 堆 方法区等

白话解释:
JVM是一台虚拟出来的一台机器,也就有自己的CPU、内存管理,比如栈、堆、方法区,所以也就有后面的JVM调优等等。

8. javac的过程

在这里插入图片描述

9. 常见的JVM实现

  1. Hotspot

    • oracle官方,我们做实验用的 JVM
    • java –version
  2. Jrockit

    • BEA,曾经号称世界上最快的 JVM
    • 被Oracle收购,合并于hotspot
  3. J9 – IBM

  4. Microsoft VM

  5. TaobaoVM

    • hotspot深度定制版 ▪
  6. LiquidVM

    • 直接针对硬件 ▪
  7. azul zing

    • 最新垃圾回收的业界标杆
    • www.azul.com

在这里插入图片描述
Hotspot:就是上面所说的第一个JVM类型
mixed mode:就是 上面 1.4说的混合模式,解释和编译混合执行。

10. JDK JRE JVM

  • jdk全称:java development kit,其意思是java开发工具包。jdk是sun公司开发的,jdk包括jre(java runtime environment)java运行环境,一堆java工具[java的编译器(java c.exe),java解释执行器(java.exe)]和java基础的类库(有3000多类,常用的类150多个)。

  • JRE(Java Runtimely Environment),java运行环境,只能运行.class文件,不能编译,针对用户。JRE,包含一个JVM(java虚拟机),与java核心类库与其所支持的文件。与JDK不同,它不包含开发工具—编译器,调试器和其他工具。

  • JVM(java Virtual Machine ) ,Java虚拟机,Java运行环境。Java虚拟机,是一种虚拟出来的计算机,是通过在实际的计算机上模拟仿真各种计算机功能来实现的。

在这里插入图片描述

二、Class File Format (class 文件格式)

分析和学习class文件。目前公司面试很少用到,但是需要学习和了解哈,抱着兴趣去学。

不能抱着功利性去学。
class文件:就是编译完成之后的 .class 文件

1、测试小程序

a、T0100_ByteCode01.java

最简单的测试小程序,就是一个类,是为了方便观察其编译后的内容,然后由简到繁,逐步学习。

package com.mashibing.jvm.c1_bytecode;

public class T0100_ByteCode01 {
}

然后编译,生成 T0100_ByteCode01.class 文件。

b、idea打开T0100_ByteCode01.class

如果在idea中打开编译后的 T0100_ByteCode01.class 的文件,就是idea会帮我们进行反编译,反编译的多了一个默认的无参构造函数,这是默认添加的。
注释是反编译出来的注释

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mashibing.jvm.c1_bytecode;

public class T0100_ByteCode01 {
    public T0100_ByteCode01() {
    }
}

2、class文件

  • 任何的文件都应该是010101二进制,class文件如果用一个16进制编辑器(sublime text 3)打开,就是如下图所示:
    在这里插入图片描述

  • class文件是 二进制字节流。

  • 数据类型:u1 u2 u4 u8 和 _info (表类型)(只是逻辑上分的,其实没有数据类型,只有0和1 )(u:Unsigned,意为为无符号的,u1指1个字节;u2指2个字节;u3指3个字节;u4指4个字节;u8指8个字节

    • _info 的来源 是Hotspot 源码中的写法
  • 查看16进制格式classFile 的工具

    • sublime(打开如上图) / notepad

    • idea插件:Bined
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      (上面的红框可以查看二进制、八进制、十六进制的文件,当然二进制是最根本的文件格式)

  • 有很多可以观察byteCode的方法

    1. javap(java自带):下面有使用
    2. JBE 可以直接修改
    3. JclassLib idea插件之一 (下面以这个工具主要讲解)
      在这里插入图片描述
      未下载前 是idea自带的
      将鼠标放在class文件或者Java文件中:
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      不好观察,所以下载插件: JclassLib
      将鼠标放在class文件或者Java文件中:
      在这里插入图片描述
      在这里插入图片描述
  • classfile构成
    看博文开头的xmind文件。

    ClassFile {
        u4             magic;
        u2             minor_version;
        u2             major_version;
        u2             constant_pool_count;
        cp_info        constant_pool[constant_pool_count-1];
        u2             access_flags;
        u2             this_class;
        u2             super_class;
        u2             interfaces_count;
        u2             interfaces[interfaces_count];
        u2             fields_count;
        field_info     fields[fields_count];
        u2             methods_count;
        method_info    methods[methods_count];
        u2             attributes_count;
        attribute_info attributes[attributes_count];
    }
    

3、Class文件解读

  1. class就是二进制字节流,那怎么解释呢,看由谁来解释,这里是由java虚拟机 JVM 来解释的,为了方便下面以16进制进行查看二进制字节流,十六进制也是 jvm 的规范进行解读。

  2. 每个十六进制 对应 jvm 制定规范的 含义和指令。比如下面的十六进制 CAFE BABE 对应就是magic number ,含义就是class文件的开头,

  3. 提前剧透:常量池是class文件里最复杂的部分

下图就是上面2.2 第一个图片,编译后的class文件,对其进行解读。
在这里插入图片描述
== 讲解上图:==

一个小格是一个字节。对十六进制来讲,一个十六进制就是4位。两个十六进制就是一个字节 即8位。(如下图可看出,第一个小格是CA,这是16进制,所以这是一个字节,即8位。)(1字节可以包含两个16进制数

  • CAFE BABE 这是java编译后class文件的抬头,比如其他png、GIF的都有自己独有的抬头。这就是 magic number 魔法数。

  • 0000 0034 中,

    • 0000minor version ,小版本号,比如版本是52.0,则minor version就是.0的概念
    • 0034major version ,大版本号,十进制是52,1.8编译完后就是52,1.9就是53。
  • 1110constant_pool_count,常量池里存在常量的个数;两个字节,216=65536,,最多可放65535个常量最多是 - 1。

  • 接着是常量的表constant_pool :这里就是存常量池的地方,这里面放的是类的一些信息,比如类名、方法、参数等等。如xmid文档,截图部分如下图。

    其长度为constant_pool_count - 1的表;这里是10,十六进制 就是15,则 就是15-1=14个常量,为什么要减一,因为常量池数组是从1开始的(平时数组是从0开始)因为最前面保留了一个0,将来可能有一些引用指向会表示不指向任意常量的任何一项,就可以用0来代表。
    在这里插入图片描述

  • access flags :访问标识,比如public、private、protect、final等。
    在这里插入图片描述

  • 后面的依次进行 翻译,这里就略过,每个十六进制数 都对应jvm的设置好的含义或者是指令可以主要看博文最开始的 xmind文件以及jvm class 格式 官网

a、javap 翻译class 文件 (java自带)

这样看不是很清楚,可以通过工具来很清晰的查看,就是java自带的javap:会把class文件中的内容帮我们翻译好。(从2.2中可以看到)
javap T0100_ByteCode01.class:显示内容较少,如下,(可通过javap查看参数)
在这里插入图片描述
javap -v T0100_ByteCode01.class:下图中可以看到帮我们翻译出来的 minor version、major version、flags 等名称。
在这里插入图片描述
flags: (0x0021) ACC_PUBLIC, ACC_SUPER:后面的 ACC_SUPER 就是:该标志必须为真,JDK1.0.2之后编译出来的内容必须为真,指明invokespectial指令使用新语义

b、jclasslib 翻译class文件(idea插件)

使用 jclasslib 打开 class 文件,下面并进行分析和说明

i、一般信息

这里包含了class 文件结构的大多数基础信息,当然最重要的还是常量池。
在这里插入图片描述

  1. 本类索引,就是 this class :cp_info #7 <com/mashibing/jvm/c1_bytecode/T0100_ByteCode01>:后面的 <com/mashibing/jvm/c1_bytecode/T0100_ByteCode01> 就是本类的名称,cp_info #7 就是在常量池的7号存的。绿色可以点击,点击过去就是 常量池的7号位置。
  2. 父类索引,就是 super class:cp_info #2 <java/lang/Object> :后面的还是父类名称,前面就是父类存储在常量池的2号位置。
  3. 接口计数 即 interfaces count。
  4. 字段计数 即 fields count。
  5. 方法计数 即 methods count。
  6. 属性计数 即 attributes count。
ii、常量池:

在这里插入图片描述

  • 常量类型有很多种,如下图所示1,3,4,5,6到18,但是没有2,标记:常量池的每一种类型前边都有一个一个字节的标记,用的最多的是第一个:CONSTANT_Utf8_info ,代表 utf8的字符串。 (下图的思维导图可从文章开头的前言中找到并下载
    在这里插入图片描述
    在这里插入图片描述
  • jclasslib 打开的常量池 1号位置Methodref_info 文件:存的是方法引用信息,从思维导图中可以看出存的如下图所示,包括三个 1是标记10,2是index2个字节指向其他常量池 ,3是index2个字节指向其他常量池。
    在这里插入图片描述
  • 1号位置 methodref_ref中的 类名 cp_info #2 :意思是指向类的名字在2号位置,这里又存在了4号位置。
    在这里插入图片描述
    在这里插入图片描述
  • 回过头来再看 1号位置 methodref_ref 中的 描述 cp_info #3 :指向的是3号位置的name和type。可以看出
    <init>: 是构造函数
    <()v>()是指 没有参数,V是指返回类型为void类型。
    在这里插入图片描述
iii、接口、字段

因为2.1测试小程序很简单,没有接口和字段,所以这里为空
在这里插入图片描述
在一般信息中,也可以看出个数,如下
在这里插入图片描述

iv、方法*****

测试小程序虽然很简单,啥都没有
但是生成一个默认的 构造函数,调用的父类也就是java.lang.Obeject的构造方法
这里也有最重要的code 环节,因为函数里会有code的哈,这里会有大量的指令集(JVM大约定义256个左右)
在这里插入图片描述

  • <init> 就是默认的构造函数,从指令的右边可以看出 调用的是父类的默认的构造方法。

  • code 就是重要的代码部分,右边的上面也有指向常量池的类名称等信息,从这里也可以看出,类方法信息也都存在了常量池中。

  • JVM 13 版本 的第七章,是十六进制码 与 指令的 对照。即 十六进制码 代表了什么意思,方法的具体实现翻译成class文件都变成了第七章(下图)的 十六进制(本质二进制)和指令(十六进制的映射),也就是 java的汇编语言
    在这里插入图片描述

  • 当前在字节码中,有三个 指令。
    指令的翻译可以从官网中查找对应的意思。

    1. 第一个是 aload_0通过上面文档可以找到(也可以通过鼠标在 jclasslib 中点进去如下图),
      在这里插入图片描述
      aload_0 对应的是 0X2a 这个十六进制,可以在class文件的十六进制文本中找到 2a 这个位置,这个位置对应的就是 aload_0 指令,那么 这个指令的作用是干嘛的呢。

      在文档中检索找到此位置,这个汇编指令代表的是:把本地变量表中的第0项(只要不是静态方法就是 this)放到栈里,然后执行第二条指令 invokespecial
      在这里插入图片描述

    2. invokespecial:可以看到右面的 #1 可以点进去进行跟踪。在文档找到描述,如下图,可以看到对应的16进制是 0Xb7。加载到栈中,然后是第三条指令,也就是最后一条指令。format中下面两个indexbyte1和indexbyte2 是指令的两个参数
      在这里插入图片描述

    3. return 返回指令,对应 b1

    4. 构造函数<init>的 三个指令 体现在十六进制的 class文件中如下所示。
      在这里插入图片描述

v、附加属性 attributes

这里默认的就是java的类名称
在这里插入图片描述

c、小总结

上面主要讲解了class文件的十六进制由JVM解释后的内容,通过JVM文档进行对应解释。

除了常量池之外的,存的内容都是常量池中的地址。

由常量池存放除常量池之外的其他内容的引用地址。
在这里插入图片描述

三、循序渐进增加内容,查看class文件

1、实现 interface 接口

a、测试小程序

package com.mashibing.jvm.c1_bytecode;

import java.io.Serializable;

public class T0101_ByteCode_With_Interfaces implements Cloneable, Serializable {
}

b、编译后class文件

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mashibing.jvm.c1_bytecode;

import java.io.Serializable;

public class T0101_ByteCode_With_Interfaces implements Cloneable, Serializable {
    public T0101_ByteCode_With_Interfaces() {
    }
}

c、jclasslib 查看

多了两个实现的接口,可以看到存在了常量池。
在这里插入图片描述
在这里插入图片描述

2、添加 函数

a、测试小程序

package com.mashibing.jvm.c1_bytecode;

public class T0102_ByteCode02 {
    void m() {
        int i=0;
        int j = i++;
    }
}

b、编译后class文件

package com.mashibing.jvm.c1_bytecode;

public class T0102_ByteCode02 {
    public T0102_ByteCode02() {
    }

    void m() {
        int i = 0;
        ++i;
    }
}

c、jclasslib 查看

可以看到 自定义方法和构造函数也都放到了常量池中。

  1. 增加了一个自定义方法。和默认的构造函数。
    在这里插入图片描述
  2. 自定义函数对应的指令。
    在这里插入图片描述

3、增加类属性

a、测试小程序

package com.mashibing.jvm.c1_bytecode;

public class T0103_ByteCode03 {
    int i = 0;
    String s = "Hello ByteCode!";
}

b、编译后的class文件

package com.mashibing.jvm.c1_bytecode;

public class T0103_ByteCode03 {
    int i = 0;
    String s = "Hello ByteCode!";

    public T0103_ByteCode03() {
    }
}

c、jclasslib 查看

类属性,即类成员变量,也存放在了常量池中。
在这里插入图片描述
在这里插入图片描述

4、增加带参构造函数和类属性

a、测试小程序

package com.mashibing.jvm.c1_bytecode;

public class T0104_ByteCode04 {
    int i = 0;
    String s = "Hello ByteCode!";

    public T0104_ByteCode04(int i, String s) {
        this.i = i;
        this.s = s;
    }
}

b、编译后的class文件

package com.mashibing.jvm.c1_bytecode;

public class T0104_ByteCode04 {
    int i = 0;
    String s = "Hello ByteCode!";

    public T0104_ByteCode04(int i, String s) {
        this.i = i;
        this.s = s;
    }
}

c、jclasslib 查看

在这里插入图片描述
在这里插入图片描述
红框中是函数参数类型和返回值类型。
在这里插入图片描述

5、增加构造函数、类方法、类属性

a、测试小程序

package com.mashibing.jvm.c1_bytecode;

public class T0104_ByteCode05 {
    int i = 0;
    String s = "Hello ByteCode!";

    public T0104_ByteCode05(int i, String s) {
        this.i = i;
        this.s = s;
    }

    public void m() {}
}

b、编译后的class文件

package com.mashibing.jvm.c1_bytecode;

public class T0104_ByteCode05 {
    int i = 0;
    String s = "Hello ByteCode!";

    public T0104_ByteCode05(int i, String s) {
        this.i = i;
        this.s = s;
    }

    public void m() {
    }
}

c、jclasslib 查看

在这里插入图片描述

在这里插入图片描述

四、如何找到 JVM class 格式 官网文档

1、直接进入网址即可

这是java 19版本的 JVM
https://docs.oracle.com/javase/specs/jvms/se19/html/index.html

2、从oracle 官网开始找

  1. 进入oracle 官网:https://www.oracle.com/,通过product 找到java 所在地进来。
    在这里插入图片描述
  2. 进入到了java页面,然后点击右上角的 download
    在这里插入图片描述
  3. 然后进入到了下载页面,也就是默认是最新的java版本,目前是19版本,如下所示
    在这里插入图片描述
  4. 拉到下面,找到 document download 中 下面的 read me,点进去
    在这里插入图片描述
  5. 然后找到如图的 jdk document 中的红框中的第一个,(这两个都有用)。
    在这里插入图片描述
  6. 这就是jdk 文档了,也可以从上面搜索任意一个版本的java版本。
    在这里插入图片描述
  7. 找到 下面的 specifications 中的 language and VM 这就是我们此行的目的地了
    在这里插入图片描述
  8. 这里就是各个版本的 jdk 文档了,同时还有每个版本新增的亮点,如下图所示,点击下面的 HTML。
    在这里插入图片描述
  9. 进入到文档(如下图所示),然后找到第四章(如下图所示),这就是 class 文件 格式的 内容了。
    在这里插入图片描述
    在这里插入图片描述

3、总结

从上面的最后一张截图所在的网址里,就可以学习 class 文件 格式的内容,也就是博文最开始总结的 xmind 的内容。
下图中就是class 文件 中 最重要的 常量池中的 tag 的标识。
在这里插入图片描述

相关文章
|
13天前
|
Java API Maven
2025 Java 零基础到实战最新技术实操全攻略与学习指南
本教程涵盖Java从零基础到实战的全流程,基于2025年最新技术栈,包括JDK 21、IntelliJ IDEA 2025.1、Spring Boot 3.x、Maven 4及Docker容器化部署,帮助开发者快速掌握现代Java开发技能。
158 1
|
20天前
|
数据采集 搜索推荐 Java
Java 大视界 -- Java 大数据在智能教育虚拟学习环境构建与用户体验优化中的应用(221)
本文探讨 Java 大数据在智能教育虚拟学习环境中的应用,涵盖多源数据采集、个性化推荐、实时互动优化等核心技术,结合实际案例分析其在提升学习体验与教学质量中的成效,并展望未来发展方向与技术挑战。
|
2月前
|
前端开发 Java API
新手 Java 学习资料结合最新技术的精选推荐及高效学习资源参考
本文为新手推荐了涵盖Java基础到最新技术的学习资料,包括官方文档、在线课程、书籍、学习网站及实践平台,帮助系统掌握Java编程,并通过Spring Boot实战提升开发能力。
94 1
|
27天前
|
存储 搜索推荐 安全
Java 大视界 --Java 大数据在智能教育学习效果评估与教学质量改进中的应用(209)
本文探讨了 Java 大数据在智能教育中的创新应用,涵盖学习效果评估、教学质量改进及个性化教学方案定制等内容,结合实战案例与代码解析,展现技术如何赋能教育智能化转型。
|
4月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
391 55
|
5月前
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
342 6
|
8月前
|
存储 设计模式 监控
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
872 166
|
10月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
1632 1
|
6月前
|
存储 缓存 算法
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
291 29
JVM简介—1.Java内存区域
|
6月前
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略