运行时数据区内存分布(上篇)
虚拟机运行时数据区下篇(堆,方法区)点击传送
概述
我们运行一个所谓的java程序,其实就是开启了一个虚拟机的进程,那这个虚拟机在程序运行时虚拟机里跟程序运行相关的内存结果有哪些呢。
图示
如图所示,相信平时大家也接触过内存图,但大部分都是堆,栈,方法区,其他的结构听说的相对性就会比较少。
每个线程都有自己独立的虚拟机栈,本地方法栈,程序计数器就是图上灰色的结构,但是方法区和堆是多线程共享的。就是说灰色部分每个线程一份,可以有多份,但是红色部分就每个虚拟机只有一份了。
图示
先讲这些共享的结构
pc寄存器
因为cpu需要不停的切换各个线程,切换回来过后就得知道接着从哪开始执行。
jvm的字节码解释器就需要通过改变PC寄存器的值来确定下一步一个需要执行什么样的字节码指令。
pc寄存器主要作用就是记录代码执行到哪一行。
本地方法栈
虚拟机栈用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用
当某个线程调用一个本地方法时,它就进入了一个全新并且不再受虚拟机限制的世界,它和虚拟机有同样的权限。
本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区
它可以访问本地处理器的寄存器 可以直接从本地内存的堆中分配任意数量的内存
虚拟机栈
栈中数据都是以栈帧的格式存在。线程执行的每个方法对应一个栈帧。
每个栈帧里面包含有局部变量表,操作数栈,动态链接,方法返回地址,还有一些附加信息
局部变量表
定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量
当一个方法实例被调用时,局部变量会按照被定义的顺序复制到局部变量表的每一个slot上,如果访问局部变量中的64位的变量值时,使用前一个索引
如果当前帧是构造方法或者实例方法 该对象引用的this就会存放在index为0的slot处。
局部变量表中的变量也是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收。
操作数栈
主要用于保存计算过程的中间过程,同时作为计算过程变量临时的存储空间
32bit的类型占用一个栈单位的深度
64bit的类型占用两个栈单位的深度
如果调用的方法有返回值,其返回值就会被压入当前栈帧的操作数栈中
动态链接(动态链接,方法返回地址,附加信息,统一叫做数据区)
每个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用 目的就是为了支持当前代码可以实现动态链接。
java源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用保存在class文件的常量池里。动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。
方法返回地址
存放调用该方法的pc寄存器的值
调用这的pc计数器的值作为返回地址,即调用该方法的指令的下一条指令的地址。
正常完成出口和异常完成出口的区别在于:通过异常完成出口退出的不会给他的上层调用者产生任何返回值
附加信息
栈帧中还允许携带域java虚拟机实现相关的一些附加信息,例如对程序调试提供支持的信息
小结
每个线程里都包含有上述的这些结构,正因为线程都有这些结构,所有各个线程之间才可以相互切换的完成工作。虚拟机栈部分还是比较重要的组成部分大家可以重点了解。
秃头萌新一枚多多关照