首先,我们应该通过题目了解到上下文是什么:run-time即运行时,即jvm启动时及启动后的存储数据的区域,而且这片区域以内存作为存储媒介,这些区域有些生命周期是随着jvm的启动和销毁而存在,有些区域则是线程维度的;为什么要将内存下面六部分,而不是七部分呢?不知道,那就先看一下这六部分的分工呗。
程序计数器(pc register)
线程私有区域,针对Java方法(非native方法),记录的是当前方法(the current method)正在执行的虚拟机字节码指令的地址(也就是执行到字节码什么位置了),如果执行native方法,计数器值为空。
存在的意义是什么:cpu执行期间,线程切换后能恢复到正确的执行位置。
虚拟机栈(jvm stacks)
我们通过它的stacks这个复数可以分析出来,这是一坨stack的聚会区域,那一个stack又是什么呢?一个stack也是线程私有区域,生命周期与线程一样,每个jvm stack存储多个栈桢(frame:对应一个方法),用官方的话就是:A Java Virtual Machine stack stores frames,
存在的意义是什么:jvm stack用来存储本地变量和部分计算结果,主要用于方法的调用和返回信息
内存管理特点:内存区域可以不连续(a Java Virtual Machine stack does not need to be contiguous),可以固定,也可以根据使用情况动态扩展。
虚拟机栈其实就是存储和管理栈桢的,下面咱们说说栈桢(stack frame)
栈桢(stack frame)
栈桢用于存储数据和部分结果,包括动态链接(dynamic link),方法返回值以及派发异常
栈桢的生命周期:方法被调用时创建一个栈桢 ,方法调用完成销毁
栈桢是用于方法调用,所以涉及方法的调用主要就需要考虑方法内部的变量,变量的指令运算,以及引用的方法外部的变量,所以栈桢由三个组成部分:
- 栈桢自己所有的局部变量表(它是一个array数组呦)
- 栈桢自己所有的操作数栈(用于变量计算)
- 当前方法类的运行时常量池(run-time constant pool)的引用
局部变量表(local variables)
局部变量表是一个数组,数组的长度在编译期就已经确定,通过所在类或接口的二进制表示形式表示(其实就是记录到字节码文件上),并且通过index定位,默认index第一位为this。
操作数栈(operand stacks)
这个不多说了,就是一个后进先出的一个栈,用于方法调用的指令计算
动态链接(dynamic link)
说到动态链接需要先说一下符号引用,想想jvm的上下文:一个java类将会编译成一个class文件,在编译时,java类并不知道所引用的类的实际内存地址,因此只能使用符号引用来代替,这就产生了符号引用。
基于符号引用,动态链接负责将符号引用转换为具体引用 。
heap(堆)
jvm共享内存,用于存放实例和数组,通过gc统一管理
方法区(method area)
jvm共享内存,存储类的结构(例如run-time constant pool),属性,方法,虽然方法区在逻辑上是堆的一部分,但简单实现上,jvm不强制要求使用垃圾收集或压缩,也不强制要求管理编译代码的策略
运行时常量池(run- time constant pool)
运行时常量池是在一个class文件中的常量池表,这个表的内容是每个class或每个interface运行时的表示形式。它包含几种常量,从编译时已知的数值文本到运行时必须解析的方法和字段引用。运行时常量池的功能类似于传统编程语言的符号表,但是它包含比典型符号表更广泛的数据范围。
存储区域:在方法区(method area)
本地方法栈(native method stacks)
线程私有