一、JVM 运行时内存结构
1. Heap 堆
Heap 堆
- 含义:主要将 存储对象实例 到内存中, 为 对象实例开辟内存空间。
- 作用:解决的是 数据存储问题。(即数据怎么放、放哪儿)
- 是否共享:线程(数据)共享,存在线程安全问题。
例如:
java
String s1 = new String("你好!我是S1");
String s2 = new String("你好!我是S2");
List<String> l3 = Stream.of("你好!我是l2").collect(Collectors.toList());
方法区(元空间)
- 含义:主要
存放类的信息
。 - 类的信息主要包含:
类的信息
、局部变量表
、方法信息
、常量池
。 - 线程安全问题:线程(数据)共享,存在线程安全问题。
- 含义:主要
例如:
MetaData.java
示例代码, 运行代码获取到MetaData.class
。
java
package com.calvin.jvm.structure;
import com.sun.org.apache.xerces.internal.impl.xpath.regex.Match;
/**
* 方法区(元空间)
*
* @author Calvin
* @date 2023/5/11
* @since v1.0.0
*/
public class MetaData {
/**
* 静态常量
*/
public static final Integer I = 100;
/**
* 字符串常量
*/
public final String A = "a";
/**
* 常量
*/
public final double b = Math.random();
/**
* 主方法信息
*
* @param args 参数
*/
public static void main(String[] args) {
// 局部: 字符串常量
String c = "c";
System.out.println(c);
}
}
- 通过 java 命令,查看
MetaData.class
汇编指令。
shell
$ javap -c -v MetaData.class
MetaData.class
汇编指令, 文件如下:
C#
Classfile /Users/calvin/学习/Jvm 虚拟机/calvin-java-jvm/chapter-02-jvm-structure/target/classes/com/calvin/jvm/structure/MetaData.class
Last modified 2023-5-11; size 919 bytes
MD5 checksum 8946635fee16f950d951859aeeb22656
Compiled from "MetaData.java"
// 类的信息
public class com.calvin.jvm.structure.MetaData
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
// 常量池
Constant pool:
#1 = Methodref #12.#35 // java/lang/Object."<init>":()V
#2 = String #36 // a
#3 = Fieldref #11.#37 // com/calvin/jvm/structure/MetaData.A:Ljava/lang/String;
#4 = Methodref #38.#39 // java/lang/Math.random:()D
#5 = Fieldref #11.#40 // com/calvin/jvm/structure/MetaData.b:D
#6 = String #31 // c
#7 = Fieldref #41.#42 // java/lang/System.out:Ljava/io/PrintStream;
#8 = Methodref #43.#44 // java/io/PrintStream.println:(Ljava/lang/String;)V
#9 = Methodref #45.#46 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
#10 = Fieldref #11.#47 // com/calvin/jvm/structure/MetaData.I:Ljava/lang/Integer;
#11 = Class #48 // com/calvin/jvm/structure/MetaData
#12 = Class #49 // java/lang/Object
#13 = Utf8 I
#14 = Utf8 Ljava/lang/Integer;
#15 = Utf8 A
#16 = Utf8 Ljava/lang/String;
#17 = Utf8 ConstantValue
#18 = Utf8 b
#19 = Utf8 D
#20 = Utf8 <init>
#21 = Utf8 ()V
#22 = Utf8 Code
#23 = Utf8 LineNumberTable
#24 = Utf8 LocalVariableTable
#25 = Utf8 this
#26 = Utf8 Lcom/calvin/jvm/structure/MetaData;
#27 = Utf8 main
#28 = Utf8 ([Ljava/lang/String;)V
#29 = Utf8 args
#30 = Utf8 [Ljava/lang/String;
#31 = Utf8 c
#32 = Utf8 <clinit>
#33 = Utf8 SourceFile
#34 = Utf8 MetaData.java
#35 = NameAndType #20:#21 // "<init>":()V
#36 = Utf8 a
#37 = NameAndType #15:#16 // A:Ljava/lang/String;
#38 = Class #50 // java/lang/Math
#39 = NameAndType #51:#52 // random:()D
#40 = NameAndType #18:#19 // b:D
#41 = Class #53 // java/lang/System
#42 = NameAndType #54:#55 // out:Ljava/io/PrintStream;
#43 = Class #56 // java/io/PrintStream
#44 = NameAndType #57:#58 // println:(Ljava/lang/String;)V
#45 = Class #59 // java/lang/Integer
#46 = NameAndType #60:#61 // valueOf:(I)Ljava/lang/Integer;
#47 = NameAndType #13:#14 // I:Ljava/lang/Integer;
#48 = Utf8 com/calvin/jvm/structure/MetaData
#49 = Utf8 java/lang/Object
#50 = Utf8 java/lang/Math
#51 = Utf8 random
#52 = Utf8 ()D
#53 = Utf8 java/lang/System
#54 = Utf8 out
#55 = Utf8 Ljava/io/PrintStream;
#56 = Utf8 java/io/PrintStream
#57 = Utf8 println
#58 = Utf8 (Ljava/lang/String;)V
#59 = Utf8 java/lang/Integer
#60 = Utf8 valueOf
#61 = Utf8 (I)Ljava/lang/Integer;
{
public static final java.lang.Integer I;
descriptor: Ljava/lang/Integer;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
public final java.lang.String A;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC, ACC_FINAL
ConstantValue: String a
public final double b;
descriptor: D
flags: ACC_PUBLIC, ACC_FINAL
public com.calvin.jvm.structure.MetaData();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String a
7: putfield #3 // Field A:Ljava/lang/String;
10: aload_0
11: invokestatic #4 // Method java/lang/Math.random:()D
14: putfield #5 // Field b:D
17: return
LineNumberTable:
line 12: 0
line 22: 4
line 27: 10
LocalVariableTable:
Start Length Slot Name Signature
0 18 0 this Lcom/calvin/jvm/structure/MetaData;
// 方法信息
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: ldc #6 // String c
2: astore_1
3: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_1
7: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
LineNumberTable:
line 36: 0
line 37: 3
line 38: 10
// 局部变量表
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 args [Ljava/lang/String;
3 8 1 c Ljava/lang/String;
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: bipush 100
2: invokestatic #9 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: putstatic #10 // Field I:Ljava/lang/Integer;
8: return
LineNumberTable:
line 17: 0
}
SourceFile: "MetaData.java"
Stack 虚拟机栈
- 含义:主要支持虚拟机 进行方法调用 和 方法执行 的数据结构。
- 作用:解决的是 运行问题。(即程序如何执行,或者如何处理数据)
- 栈数据结构原则:先进后出,后进先出。
栈帧
的内部结构主要包含:- 局部变量表
- 操作数栈
- 动态链接
- 方法出口
例如:
StackFrame.java
示例代码, 运行如下代码。
java
package com.calvin.jvm.structure;
/**
* 栈帧
*
* @author Calvin
* @date 2023/4/25
* @since v1.0.0
*/
public class StackFrame {
/**
* B 方法
*/
public void b() {
System.out.println("我是B方法");
}
/**
* A 方法
*/
public void a() {
b();
System.out.println("我是A方法");
}
/**
* 主方法
*
* @param args 参数
*/
public static void main(String[] args) {
new StackFrame().a();
}
}
- 输出结果
log
我是B方法
我是A方法
Native 本地方法栈
- 含义:使用 Java 代码调用 C 语言(Java Native Interface), 简称 JNI。
程序计数器(PC寄存器)
- 含义: 在多线程情况下,线程上下文切换时,记录 线程执行行号。
3. 执行引擎
执行引擎(Execution Engine)
:- 4 大部分: 解释器(Interpreter)、及时编译器(JIT Compiler)、分析器(Profiler)、垃圾回收器(Garbage Collection)