接下来的几篇博客只是对JVM的一个简单认知,主要是对JVM的组成部分以及程序的运行流程的一个介绍,并没有深入到每一个层次的每一个点,如果有错或者以后掌握到更深入层次的知识后,还会更新的。
JVM:Java Virtual Machine(Java虚拟机)
先看一张图,在最开始接触Java的时候的HelloWorld的运行:
我们编写的Java文件,经过javac指令,编译成为class字节码文件,再将字节码文件放到Java运行环境中运行。我们都知道,Java是个跨平台的语言,那么如何实现在windows环境以及linux环境都可以运行呢?JVM就起到了关键作用。JVM就是从软件层面屏蔽不同操作系统在底层硬件与指令的不同。
那么,JVM到底是什么,或者说长什么样呢?
我们来看下JVM的模型图:
可以看到,JVM主要由三部分组成:类装载子系统、运行时数据区、字节码执行引擎。其中运行时数据区则是主要部分。
首先来看栈部分:栈用来存储局部变量。
先来看一段简单代码:
package com.hpu.dong;
public class test {
public static final int m=100;
public static User user=new User();
public int add(){
int a=1;
int b=2;
int c=(a+b)*10;
return c;
}
public static void main(String[] args) {
test t=new test();
t.add();
System.out.println("test");
}
}
比如main方法中的t,以及add方法中的a,b,c等都是局部变量,这些变量在JVM中都存放到栈部分。
需要注意的是每一个线程都会对应一块属于自己的栈内存空间,也就是说栈是独享的。
栈帧
栈帧:每个线程的栈内存中,每个方法对应一块栈帧内存区域。
当方法调用完之后,对应的方法栈帧就会被释放掉。
这里的栈的特点与数据结构中的栈的特性也是一样的,先进后出。比如先调用了main栈帧,然后是add方法,等用完释放的时候,先释放的是后添加的方法栈帧。
栈帧组成
栈帧由局部变量表、操作数栈、动态链接、方法出口等部分组成。
局部变量表由名字就可以看出是存放局部变量的一个表。
借助字节码文件,来进一步完成对局部变量和操作数栈的理解:
打开对应class的控制台:
输入:javap -c test.class>test.txt,将字节码打印到一个txt文件中。
打印完毕之后,打开txt文件:可以看到
我们以add方法为例,
第一行代码:iconst_1:查阅JVM指令手册可以看到是将int类型常量1压入操作数栈。
第二行代码:istore_1:将int类型值存入到局部变量1中。
那么这是什么意思呢?
操作数栈和局部变量表分别对应一块区域,第一行代码表示将1压入操作数栈,第二行代码表示在局部变量表中生成一块区域,存放变量a,并将1赋值给a,赋值完毕后,操作数栈中的数就会消失。
接着走,iload_1:将从局部变量1中装载int类型的值。也就是将局部变量表中的值赋给操作数栈。
至于变量b则是与变量a完全相同的操作。
程序计数器
程序计数器是什么?回到上面字节码的图片中,发现每个方法中都有一个Code,而正对着code的下面都是从0开始的数字。
程序计数器就是存储正在运行的代码的位置,也就是code下面的数字。
那么为什么要设置程序计数器呢?
假如程序执行到某个位置,这个线程的cpu时间片被其他线程所抢占,等到其他线程使用完毕后,cpu可以根据程序计数器来继续执行代码,而不需要从头开始执行。
每运行完一行代码,程序计数器的值就会被字节码执行引擎所修改。
来源:CSDN
作者:夜笙孤酒
链接:https://blog.csdn.net/weixin_44298615/article/details/104128157