运行原理
Jvm运行时数据区
jvm运行时数据区分为: 线程共享和线程独占两个部分
JVM运行时数据区:
线程共享部分: 所有线程都能访问到的区域, 随着虚拟机或GC创建和销毁
方法区: .class的信息, 常量, 静态变量, 编译后的代码等数据存在方法区. Java8中, 它存放在元数据空间, 并通过GC对这个区域管理;
堆内存: 存储对象的区域, 垃圾回收就是指回收该区域的内容. 分为老年代, 新生代(新生代又分为Eden, From Survivor, To Survivor).
线程独占部分: 每个线程自己开辟的空间, 随着线程的生命周期创建和销毁
虚拟机栈: 是为虚拟机执行Java方法准备的空间. 线程存放栈帧的私有空间. 线程每执行一个方法, 对应一个栈帧.
栈帧中的内容: 局部变量表, 操作数栈, 动态链接, 方法返回地址, 附加信息等.
栈内存的默认大小: 1M, 超出会抛StackOverflowError.
本地方法栈: 是为虚拟机执行Native本地方法准备的空间. 通过抛StackOverflowError.
程序计数器: 记录Java程序当前线程执行字节码的位置, 存储字节码的指令地址, 如果执行Native方法, 计数器值为null. 该区域的作用是记录当前线程的执行位置, 当CPU执行其他线程完事后, 回到当前线程, 需要通过计数器知道恢复到的执行位置.
class文件内容
准备一个测试用的.java文件,
public class Demo1{
public static void main(String[] args){
int x = 500;
int y = 100;
int a = x / y;
int b = 50;
System.out.println(a + b);
}
}
打开Windows Powershell, cd到.java文目录
编译Demo1.java
javac Demo1.java
将编译后的.class文件内容导出到.txt
javap -v Demo1.class > Demo1.txt
打开.txt文件, 可以看到如下内容:
-
文件位置, 占用容量等基本信息:
Classfile /C:/Git/Demo1.class Last modified 2020-5-10; size 414 bytes MD5 checksum ae6fa820973681b35609c75631cb255b
-
java文件有关信息
Compiled from "Demo1.java" public class Demo1 minor version: 0 // 次版本号 major version: 52 // 主版本号: JDK5, 6, 7, 8 分表对应49, 50, 51, 52 flags: ACC_PUBLIC, ACC_SUPER // 访问标志
-
常量池
Constant pool: #1 = Methodref #5.#14 // java/lang/Object."<init>":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = Methodref #17.#18 // java/io/PrintStream.println:(I)V #4 = Class #19 // Demo1 #5 = Class #20 // java/lang/Object #6 = Utf8 <init> #7 = Utf8 ()V #8 = Utf8 Code #9 = Utf8 LineNumberTable #10 = Utf8 main #11 = Utf8 ([Ljava/lang/String;)V #12 = Utf8 SourceFile #13 = Utf8 Demo1.java #14 = NameAndType #6:#7 // "<init>":()V #15 = Class #21 // java/lang/System #16 = NameAndType #22:#23 // out:Ljava/io/PrintStream; #17 = Class #24 // java/io/PrintStream #18 = NameAndType #25:#26 // println:(I)V #19 = Utf8 Demo1 #20 = Utf8 java/lang/Object #21 = Utf8 java/lang/System #22 = Utf8 out #23 = Utf8 Ljava/io/PrintStream; #24 = Utf8 java/io/PrintStream #25 = Utf8 println #26 = Utf8 (I)V
-
构造器
public Demo1(); 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 1: 0
-
main方法
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=5, args_size=1 0: sipush 500 3: istore_1 4: bipush 100 6: istore_2 7: iload_1 8: iload_2 9: idiv 10: istore_3 11: bipush 50 13: istore 4 15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 18: iload_3 19: iload 4 21: iadd 22: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 25: return
程序运行分析
- 编译后, 将类信息存储到方法区(元数据空间
- 运行代码, JVM创建线程执行代码, 在虚拟机栈, 程序计数器上分配空间
- 虚拟机栈中分为本地变量表和操作数栈. 每一行代码在操作数栈中, 每执行一行, 删去一行. 如果这行代码产生了变量, 计入本地变量表