本文已参与「新人创作礼」活动,一起开启掘金创作之路。
JVM中的Java虚拟机栈
一、虚拟机栈的基本内容
1、概述
Java虚拟机栈是线程私有的。每个线程在创建时都会创建一个虚拟机栈,栈内部保存一个个的栈帧。一个栈帧对应一个方法,随着方法的调用和执行完毕,相应的栈帧执行入栈和出栈。
在java程序中,main方法是一个主线程。
2、特点
- 生命周期和线程保持一致;
- 主管Java程序的运行,栈是运行时的单位,堆是存储的单位,也就是说:==栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿==;
- 栈保存方法的局部变量(8种基本数据类型、对象的引用地址),部分结果,并参与方法的调用和返回。==这里的对象的引用地址指的就是地址,对象是在堆中存放,每个对象均有一个地址,栈中存放的就是这个地址(指针)==;
- 栈存在溢出(OOM)问题,不存在垃圾回收(GC)问题
二、栈的内部结构和运行原理
1、内部结构
- 栈中的数据是以栈帧的格式存在,栈帧是一个内存块,维系着方法执行过程中的数据信息;
- 局部变量表
- 操作数栈(或表达式栈)
- 动态链接(或指向运行时常量池的方法引用)
- 方法返回地址
2、运行原理
- 只有入栈和出栈操作;
- 在一条活动线程中,一个时间点上只有一个活动的栈帧。也就是说只有当前正在执行的方法的栈帧是有效的——当前栈帧(Current Frame),也就是栈顶栈帧;
- 执行引擎中的所有字节码指令只对当前栈帧操作有效;
- 如果当前方法内又调用其他方法,那么就会有一个新的栈帧入栈,成为栈顶栈帧;
- 不同的线程中,栈帧之间是不可能相互引用的;
- Java中有两种返回函数的方式,return指令和抛出异常,这两种方式都会使当前栈帧被弹出;
三、局部变量表结构
局部变量表又称为局部变量数组
- 它定义为一个数组,主要用于存储方法参数和==方法体内==的局部变量(在这里要和类中的成员变量区分开来);
- 局部变量表中的存储空间以局部变量槽(Slot)来表示,64位长度的类型占用两个,32位的占用一个,并且局部变量表的内存空间(即变量槽的数量)是在编译的时候就已经确定(编译过程是在进入JVM之前进行的);
- 方法嵌套的调用次数由栈的大小来决定,而栈的大小依赖于局部变量表;
四、其他
1、数据类型
Java中有两种数据类型:基本数据类型和引用类型。
(1)基本数据类型
- 8种基本数据类型:byte,short,int,long,char,float,double,boolean;
- 其代表的值就是其本身,具有固定的长度;
(2)引用数据类型
- 类、数组、接口;
- 其代表的并不是对象本身,而是对象的地址,代表某个对象的引用;
2、javap -v 字节码文件名.class
在idea中的local中输入:javap -v 字节码文件名.class
可以对字节码文件进行解析,可以查看栈帧信息、常量池信息等。
ps:在输入命令前要使用cd命令进入到文件目录
也可以在idea中安装jclasslib Bytecode viewer插件进行可视化。
本地方法栈
Java和C++之间有一堵由内存动态分配和垃圾回收技术所围成的高墙,墙外面的内向进去,墙里面的人想出来。------《深入理解Java虚拟机》
Native是java访问不到的地方,属于调用底层的C语言。(不是java来实现的方法体) Java在启动一个线程时,会调用start方法,start方法内部有一个start0方法,这个方法就进入本地方法栈,==本地方法栈时用于管理本地方法的调用,而Java虚拟机栈是管理Java方法的调用==。 在本地方法栈(Native Method Stack)中,调用本地方法,通过本地方法接口(JNI)来实现对本地方法库的访问。
为什么会有这种操作呢?
- 在Java语言创立之初,C、C++可谓是风靡全球,java语言想要立足,必须要有可调用C、C++程序的接口。随着Java语言的发展,现在不仅调用C/C++程序,也可以调用Python等语言的程序,这就可以融合不同的语言为Java所用!
- 当Java与底层硬件交互或者与操作系统交互的时候,JVM并不是一个完整的系统,它还要依赖于底层系统的支持,通过本地方法,JVM可以方便的和底层系统如操作系统进行交互。
对于程序员们来说,可能并不常用Native,一般在Java驱动打印机,系统管理生产设备(说白了就是现实生活中的实际设备)的等应用时需要Native。 但是目前针对上述的应用,我们可以使用套接字Socket、http等技术实现通信,所以使用Native更加少了。