Java虚拟机入门
Java虚拟机的工作原理, 大致可以分为以下步骤: 首先Java源文件(.java文件)经过编译器(javac命令等)将代码编译为字节码文件(.class文件), 然后加载字节码文件, 载入系统分配给JVM的内存区, 然后执行引擎解释或编译类文件, 再由即时编译器将字节码转化为机器码.
1. JVM运行时数据区

1.1 方法区
属于共享内存区域. 存储被JVM加载的类信息、常量、静态变量、编译后的代码等数据。
1.2 堆内存
堆内存可以细分为: 老年代, 新生代. 在JVM启动时创建, 存放对象的实例, 对于大多数应用来说,这块区域是JVM所管理的内存中最大的一块.
1.3 虚拟机栈
每一个线程在虚拟机栈中有一个私有的空间, 在每一个方法执行时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息. 每一个方法从调用直至执行结束, 就对应着一个栈帧从虚拟机栈中入栈到出栈的过程.
1.4 本地方法栈
和虚拟机栈功能类似, 不同的是本地方法栈是为虚拟机使用native本地方法而准备的.
1.5 程序计数器
记录当前线程执行字节码的位置, 存储的是字节码指令地址, 如果执行native方法, 计数器值为空. jvm通过改变这个计数器的值来获取下一条需要执行指令的字节码指令.
2. class文件解析
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);
}
}
创建一个类Demo1, 执行javac进行编译获取class文件, 之后执行javap -v Demo1.class > Demo1.txt进行class文件解析.
2.1 版本号
public class Demo1
minor version: 0 // 次版本号
major version: 52 // 主版本号, 表示jdk8. 5, 6, 7, 8分别对应49, 50, 51, 52
flags: ACC_PUBLIC, ACC_SUPER // 访问标志
打开txt文件可以找到以上内容. 其中访问标志可以查看以下内容.

2.2 常量池
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
继续往下阅读, 可以看到类信息包含的常量池.

2.3 构造方法
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
接续往下阅读, 可以看到类的构造函数. 在Demo1中, 我们并没有写构造函数, 由此可见, 没有定义构造函数时, 会有隐式的无参构造函数.
2.4 main方法

接续往下阅读, 可以看到程序的入口main方法. 具体的说明可以查看图片中的注释. 具体的指令可以自行查阅.
2.5 程序执行过程

3. 总结
本文主要将JVM运行的核心逻辑进行了解析, 需要注意的是, JVM运行原理中更底层的实现, 针对不同的操作系统会有不同的实现, 这也是JAVA能实现一次编写, 处处运行的原因.
浙公网安备 33010602011771号