概念: Java虚拟机在执行Java程序过程会把内存划分为若干个区域,大致可以分为线程共享区和线程私有区,如图:
线程私有区
每个线程都有自己的虚拟机栈、本地方法栈、程序计数器
1.虚拟机栈:
存储当前线程运行方法所需的数据、指令、返回地址且虚拟机栈以栈帧的形式存储。
看下面简单的代码
public class Test {
public static void main(String[] args) {
work();
}
public static int work(){
int x = 1;
int y = 2;
int z = (x + y)*2;
return z;
}
}
当我们开始执行,虚拟机栈会发生什么呢?
- 启用main线程,执行main方法
- main方法以栈帧的形式压入虚拟机栈
- 调用work方法,压入虚拟机栈
- work方法执行完毕,弹出栈
- main方法执行完毕,弹出栈
如图:
而方法执行到弹出的过程又发生了什么捏?
首先我们分析下栈帧的组成:
- 局部变量表:用于存放方法参数和方法内部定义的局部变量
- 操作数栈:JVM的解释执行的引擎
- 动态连接:java动态语言的特性,这里暂时不讲
- 完成出口:方法退出的返回
而方法的调用过程就是JVM执行操作数栈的过程。
为了更好得演示JVM操作栈,我们使用javap -c 指令对class文件进行反汇编,下图是反汇编得到的执行指令,那么他们代表什么意思捏?我们不必记住它们,点击jvm字节码指令集就可以看到所有指令集解释。
通过查看我们可以得到iconst_1 : 将int型(1)推送至栈顶
然后得到istore_0 :将一个数值从操作数栈存储到局部变量表
这就是jvm指令操作的过程,后面的指令就不解释啦,有兴趣的可以自己看看。
ps: 栈帧与栈帧之间还涉及一个栈的优化技术:前后两个栈帧可以共享一部分区域来传递参数,如图所示:
2.程序计数器:
字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令
看下图指令前面有一个数,程序计数器记录的就是这个数
那么,问题来了,我直接执行就行了,为啥还要多弄一个计数器来记录捏?
这里涉及一个概念就是操作系统的cpu轮转机制,打开任务管理器,我们可以看到我的电脑有8个逻辑处理器,所以我能同一时刻运行的线程数为8,但是实际上往往不止,这是因为cpu可以切割为很多时间片,1s对于我们来说就是一瞬间,但对于cpu来说1s可以切割为1000个1ms,而多个线程可以在1s里来回切换。
如线程1占用了第一个1ms,执行了一些指令,线程2占用了第二个1ms,然后线程1又回来占用了第三个1ms,执行剩下的指令。
对cpu来说就是来回切换,但对我们人来说看起来就是同时运行,而程序计数器的作用就是记录当前运行到的指令的位置,以便下次切换回来可以继续执行剩下的指令。
3.本地方法栈:
本地方法栈则是为了执行native方法所服务的所以本地方法也是一个私有的内存区域,一个Native Method就是一个Java调用非Java代码的接口。
本文结束啦,有什么疑问,或者本文有什么问题,都可以在评论区里面给我留言哦~