JVM知识体系

认识JVM

认识JVM规范:重点是理解JVM规范的作用,了解JVM规范的主要内容

认识JVM:是什么、有什么、能干什么
JVM:Java virtual machine,也就是java虚拟机

所谓的虚拟机是指:通过软件模拟的具有完整硬件系统功能、运行在一个完全隔离环境中的计算机系统

JVM是通过软件来模拟Java字节玛的指令集,是Java程序运行的环境

java如何实现平台无关

JVM概述图

JVM主要功能
1、通过ClassLoader寻找和装在class文件
2、解释字节码成为指令并执行,提供class文件运行环境
3、运行期间内存非配
4、提供硬件交互的平台

虚拟机是平台无关的保障

虚拟机是平台无关的保障

JVM规范作用
1.Java虚拟机规范为不同的硬件平台提供了一种编译Java技术代码的规范。
2.该规范使用Java软件独立于平台,因为编译是针对作为虚拟机的“一般机器”而做。
3.这个“一般机器”可用软件模拟并运行于各种现存的计算机系统,也可用硬件来实现。

JVM规范定义的主要内容
字节码指令集(相当于中央处理器CPU),详看JVM虚拟机规范
class文件格式
数据类型和值,详看JVM虚拟机规范
运行时数据区
栈帧
特殊方法
<init>:实例初始化方法,通过invokespecial指令来调用
<clinit>:类或接口的初始化方法,不包含参数,返回void
类库
Java虚拟机必须要对一些Java类库提供支持,否则这些类库根本无法实现,比如(反射、加载和创建类或接口,如ClassLoader、连接或初始化类和接口的类、安全,如security、多线程、弱引用)
异常处理
虚拟机的启动、加载、链接和初始化

Java虚拟机规范下载地址
https://docs.oracle.com/javase/specs/index.html

class文件格式

  • class文件是JVM的输入,Java虚拟机规范中定义了Class文件结构。Class文件Jvm实现平台无关、技术无关的基础

    • 1.class文件是一组以8字节为单位的字节流,各个数据项目按顺序紧凑排列

    • 2.对于占用空间大于8字节的数据项,按照高位在前的方式分割成多个8字节进行存储

    • 3.class文件格式里面只有两种类型:无符号数、表,详看JVM虚拟机规范

      • (1)无符号数:基本数据类型,以u1、u2、u4、u8来代表几个字节的无符号数

      • (2)表:由多个无符号数和其他表构成的符合数据类型,通常以“_info”结尾

  • javap工具生成非正式的“虚拟机汇编语言”,格式如下

1
<index> <opcode> [<operand1> [<operand2> ...]][<comment>]
  • <index>是指令操作码在数组种的下标,该数组以字节的形式存储当前方法的Java虚拟机代码;也可以是相对方法起始处的字节偏移量

  • <opcode>是指令的助记码、<operand>是操作数、<comment>是注释

class文件格式说明

  • constant_pool_count:是从1开始的

  • 不同的常亮类型,用tag来区分的,它后面对应的info结构是不一样的

  • L表示对象,[表示数组,V表示void

  • 了解预定义attribute的含义

  • stack:方法执行时,操作栈的深度

  • Locals:局部变量所需的存储空间,单位是slot

  • slot:是虚拟机为局部变量分配内存所使用的最小单位

  • arg_size:参数个数,为1的话,因实例方法会默认传入this,locals也会预留一个slot来存放

TestJVM.java原始文件

1
2
3
4
5
6
7
8
9
10
package world.ismyfree.demo;

public class TestJvm {

public static final String HELLO_JAVA = "hello java";

public static void main(String[] args) {
System.out.println(String.format("get message = %s", HELLO_JAVA));
}
}

TestJVM.class原始文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
cafe babe 0000 0034 002d 0a00 0400 1909
001a 001b 0800 1c07 001d 0700 1e08 001f
0a00 2000 210a 0022 0023 0100 0a48 454c
4c4f 5f4a 4156 4101 0012 4c6a 6176 612f
6c61 6e67 2f53 7472 696e 673b 0100 0d43
6f6e 7374 616e 7456 616c 7565 0100 063c
696e 6974 3e01 0003 2829 5601 0004 436f
6465 0100 0f4c 696e 654e 756d 6265 7254
6162 6c65 0100 124c 6f63 616c 5661 7269
6162 6c65 5461 626c 6501 0004 7468 6973
0100 1d4c 776f 726c 642f 6973 6d79 6672
6565 2f64 656d 6f2f 5465 7374 4a76 6d3b
0100 046d 6169 6e01 0016 285b 4c6a 6176
612f 6c61 6e67 2f53 7472 696e 673b 2956
0100 0461 7267 7301 0013 5b4c 6a61 7661
2f6c 616e 672f 5374 7269 6e67 3b01 000a
536f 7572 6365 4669 6c65 0100 0c54 6573
744a 766d 2e6a 6176 610c 000c 000d 0700
240c 0025 0026 0100 1067 6574 206d 6573
7361 6765 203d 2025 7301 0010 6a61 7661
2f6c 616e 672f 4f62 6a65 6374 0100 1b77
6f72 6c64 2f69 736d 7966 7265 652f 6465
6d6f 2f54 6573 744a 766d 0100 0a68 656c
6c6f 206a 6176 6107 0027 0c00 2800 2907
002a 0c00 2b00 2c01 0010 6a61 7661 2f6c
616e 672f 5379 7374 656d 0100 036f 7574
0100 154c 6a61 7661 2f69 6f2f 5072 696e
7453 7472 6561 6d3b 0100 106a 6176 612f
6c61 6e67 2f53 7472 696e 6701 0006 666f
726d 6174 0100 3928 4c6a 6176 612f 6c61
6e67 2f53 7472 696e 673b 5b4c 6a61 7661
2f6c 616e 672f 4f62 6a65 6374 3b29 4c6a
6176 612f 6c61 6e67 2f53 7472 696e 673b
0100 136a 6176 612f 696f 2f50 7269 6e74
5374 7265 616d 0100 0770 7269 6e74 6c6e
0100 1528 4c6a 6176 612f 6c61 6e67 2f53
7472 696e 673b 2956 0021 0005 0004 0000
0001 0019 0009 000a 0001 000b 0000 0002
0006 0002 0001 000c 000d 0001 000e 0000
002f 0001 0001 0000 0005 2ab7 0001 b100
0000 0200 0f00 0000 0600 0100 0000 0300
1000 0000 0c00 0100 0000 0500 1100 1200
0000 0900 1300 1400 0100 0e00 0000 4300
0600 0100 0000 15b2 0002 1203 04bd 0004
5903 1206 53b8 0007 b600 08b1 0000 0002
000f 0000 000a 0002 0000 0008 0014 0009
0010 0000 000c 0001 0000 0015 0015 0016
0000 0001 0017 0000 0002 0018

javap -verbose TestJVM.class(助记符)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
Classfile /home/anakin/IdeaProjects/untitled/target/classes/world/ismyfree/demo/TestJvm.class
Last modified 2021-8-8; size 764 bytes
MD5 checksum b5c5da06a2ed9a50c599a61bf2f71066
Compiled from "TestJvm.java"
public class world.ismyfree.demo.TestJvm
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#25 // java/lang/Object."<init>":()V
#2 = Fieldref #26.#27 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #28 // get message = %s
#4 = Class #29 // java/lang/Object
#5 = Class #30 // world/ismyfree/demo/TestJvm
#6 = String #31 // hello java
#7 = Methodref #32.#33 // java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
#8 = Methodref #34.#35 // java/io/PrintStream.println:(Ljava/lang/String;)V
#9 = Utf8 HELLO_JAVA
#10 = Utf8 Ljava/lang/String;
#11 = Utf8 ConstantValue
#12 = Utf8 <init>
#13 = Utf8 ()V
#14 = Utf8 Code
#15 = Utf8 LineNumberTable
#16 = Utf8 LocalVariableTable
#17 = Utf8 this
#18 = Utf8 Lworld/ismyfree/demo/TestJvm;
#19 = Utf8 main
#20 = Utf8 ([Ljava/lang/String;)V
#21 = Utf8 args
#22 = Utf8 [Ljava/lang/String;
#23 = Utf8 SourceFile
#24 = Utf8 TestJvm.java
#25 = NameAndType #12:#13 // "<init>":()V
#26 = Class #36 // java/lang/System
#27 = NameAndType #37:#38 // out:Ljava/io/PrintStream;
#28 = Utf8 get message = %s
#29 = Utf8 java/lang/Object
#30 = Utf8 world/ismyfree/demo/TestJvm
#31 = Utf8 hello java
#32 = Class #39 // java/lang/String
#33 = NameAndType #40:#41 // format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
#34 = Class #42 // java/io/PrintStream
#35 = NameAndType #43:#44 // println:(Ljava/lang/String;)V
#36 = Utf8 java/lang/System
#37 = Utf8 out
#38 = Utf8 Ljava/io/PrintStream;
#39 = Utf8 java/lang/String
#40 = Utf8 format
#41 = Utf8 (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
#42 = Utf8 java/io/PrintStream
#43 = Utf8 println
#44 = Utf8 (Ljava/lang/String;)V
{
public static final java.lang.String HELLO_JAVA;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: String hello java

public world.ismyfree.demo.TestJvm();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lworld/ismyfree/demo/TestJvm;

public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=6, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String get message = %s
5: iconst_1
6: anewarray #4 // class java/lang/Object
9: dup
10: iconst_0
11: ldc #6 // String hello java
13: aastore
14: invokestatic #7 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
17: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: return
LineNumberTable:
line 8: 0
line 9: 20
LocalVariableTable:
Start Length Slot Name Signature
0 21 0 args [Ljava/lang/String;
}
SourceFile: "TestJvm.java"

ASM开发

认识ASM

  • ASM是一个Java字节码操纵框架,它能用来动态生成类或者增强既有类的功能

  • ASM能直接产生二进制class文件,也可以在类被加入虚拟机之前动态改变类行为,ASM类文件读入信息后,能够改变类行为,分析类信息,甚至能根据要求生成新类。

  • 目前许多框架如cglib、Hibernate、Spring都直接或间接地使用ASM操作字节码

ASM编程模型

  • Core API:提供了基于事件形式的编程模型。该模型不需要一次性将整个类的结构读取到内存中,因此这种方式更快,需要更少的内存,但这种编程方式难度较大。

  • Tree API:提供了基于树形的编程模型。该模型需要一次性将一个类的完整结构全部读取到内存当中,所以这种方法需要更多的内存,这种编程方式较简单。

ASM核心API

ASM的Core API

  • ASM Core API种操纵字节码的功能基于ClassVisitor接口。这个接口种的每个方法对应了class中的每一项。

  • ASM提供了三个基于ClassVisitor接口的类实现class文件的生成和转换

    • 1.ClassReader:ClassReader解析一个类的class字节码

    • 2.ClassAdapter:ClassAdapter是ClassVisitor的实现类,实现要变化的功能

    • 3.ClassWriter:ClassWriter也是ClassVisitor的实现类,可以用来输出要变化的字节码

ASMifier

  • 1.ASM给我们提供了ASMifier工具帮助开发,可以使用ASMifier工具生成ASM结构来对比

  • 2.工具Maven依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>9.2</version>
</dependency>
  • 3.idea使用maven命令将jar包copy到当前项目的dependency目录方便调试
1
mvn dependency:copy-dependencies
  • 4.执行命令使用工具解析字节码
1
java -cp .:../dependency/asm-9.2.jar:../dependency/asm-util-9.2.jar org.objectweb.asm.util.ASMifier world.ismyfree.jvm.asm.CC

如果本文对你有所帮助,请赏我1个铜板买喵粮自己吃,您的支持是我最大的动力!!!