JVM执行原理你是否已经get

JVM 运行时的数据区

.java 源代码通过编译成.class 字节码文件,将字节码文件运行在JVM中。接下来一起探讨JVM运行时都有哪些数据区域。先上一张结构图:

在这里插入图片描述

线程共享

线程共享:每个线程都能访问这块内存数据,随着虚拟机或者GC而创建和销毁。
由图可知,线程共享分为:方法区和堆内存。

方法区

方法区:用来存储加载类信息,常量,静态变量,编译后的代码等数据。
方法区存放着类的版本,字段,方法,接口和常量池。

堆内存

堆内存:JVM启动时创建,存放对象的实例。垃圾回收器主要就是管理堆内存。如果满了就会出现OOM。细分为:老年代,新生代,(Eden,From Survivor,To Suvivor。

线程独占

线程独占:每个线程都会有它独立的空间,随生命周期而创建和销毁。
由图可知,线程独占分为:虚拟机栈,本地方法栈,程序计数器。

虚拟机栈

虚拟机栈:为虚拟机执行Java方法而准备的
每个线程都在这个空间有一个私有的空间,由多个栈帧组成(Stack Frame)组成
一个线程会执行一个或多个方法,一个方法对应一个栈帧。
栈帧内容包含:局部变量表,操作数栈,动态链接,方法返回地址,附加信息
栈内存默认最大1M,超出则抛出StackOverFlowError。

本地方法栈

本地方法栈:为虚拟机执行Native 本地方法而准备的
虚拟机规范没有规定具体的实现,由不同的虚拟机厂商去实现。
HotSpot虚拟机中虚拟机栈和本地方法栈的实现方式是一样的,同样超出大小以后也会抛出StackOverFlowError。

程序计数器(Program Counter Register)

程序计数器:用来记录当前线程执行字节码的位置,存储的字节码指令地址,如果执行Native方法,则计数器为空。每个线程都在这个空间有一个私有空间,占用内存空间很少。
CPU同一时间,只会执行一条线程中的指令,JVM多线程会轮流切换并分配CPU执行时间的方式,为了线程切换后,需要通过程序计数器来恢复正确的执行位置。

案例一分析

代码示例

public class Demo1 {
    public static void main(String[] args) {
        int x = 500;
        int y = 100;
        int z = x / y;
        System.out.println(z);
    }
}

在文件所在目录执行编译及其反编译命令:

javac Demo1.java
javap -v Demo1.class

得到Demo1对应的指令码:
在这里插入图片描述

运行过程分析

1)将主函数中的args放入本地变量表中,程序开始执行:
在这里插入图片描述
2)将500 压入操作数栈,再同步到本地变量表中,程序计数器记录代码执行到第3行在这里插入图片描述
3)同样的操作,代码执行到第6行:在这里插入图片描述
4)将x/y的结果放到本地变量表中,代码执行到第10行:
在这里插入图片描述
在这里插入图片描述
5) 执行完毕,返回结果

案例二分析

代码示例

public class Demo2 {
    public static void main(String[] args) {
        int j = 0;
        for (int i = 0; i < 10; i++) {
            j = j++;
        }

        System.out.println(j);
    }
}

同样执行编译和反编译查看指令码:

javac Demo2.java
javap -v Demo2.class

运行过程分析

1) 初始化变量j在这里插入图片描述
2) 初始化for循环中的变量i:在这里插入图片描述
3) 执行for循环初始化:在这里插入图片描述
4)开始循环:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5)循环结束,返回结果为0:

在程序计数器执行到11行的时候,对于JVM来说,先把j = 0 的值压入到了操作数栈,,而在本地变量表中执行自增,但是操作数栈中还是原来的值。因此得到最后j的值始终是0;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章