这里强烈推荐看一下我jvm复习1中的知识框架,关于内存布局这块,我觉得我梳理的流程还是不错的了。
不过作为学习的话,光有框架是肯定不够的,我们需要将架子里面的内容填充完善。我来简单讲讲内存区域吧,强烈推荐看书
运行时的内存区域
程序计数器
程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的 字节码的行号指示器。在Java虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器 的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处 理、线程恢复等基础功能都需要依赖这个计数器来完成。
注:是唯一一个不会OOM的区域
虚拟机栈
简单来说,就是执行java方法的一个内存模型。每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧。栈帧用于存储局部变量表、操作数栈、动态连接、方法出口等信 息。
局部变量表
局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、int、 float、long、double)、对象引用(reference类型,它并不等同于对象本身,可能是一个指向对象起始 地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress 类型(指向了一条字节码指令的地址)。
操作数栈
当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种 字节码指令往操作数栈中写入和提取内容,也就是出栈和入栈操作。譬如在做算术运算的时候是通过 将运算涉及的操作数栈压入栈顶后调用运算指令来进行的,又譬如在调用其他方法的时候是通过操作 数栈来进行方法参数的传递。
动态连接
Class文件的常量池中存 有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就被转化为直接引用,这种转化被称为静态解析。 另外一部分将在每一次运行期间都转化为直接引用,这部分就称为动态连接
方法返回
在方法退出之后,都必须返回到最初方法被调用时的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层主调方法的执行状态。这就是方法返回。
本地方法栈
简而言之,虚拟机栈式执行java方法的,而本地方法栈是执行本地方法,也就是不是java方法的一些方法。其他构造是类似虚拟机栈。
java堆
简单来说,java堆是一个存放对象的区域。
在早期的jdk(1.6之前)方法区,虽然逻辑上不属于堆中但是实际上确实是在堆中,所以那时候的方法区也被叫做永久代。后来关于静态变量,字符串常量池就放在堆中(1.7),方法区的其余部分就放在了元空间(1.8)。
而且堆中其实还有线程私有的分配缓冲区,当然也是属于共享空间的。这里可能不太好理解,但是简单理解就是都要用来gc的。分配的区域可能再分配的。
方法区
方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载 的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
运行时常量池
运行时常量池是方法区的一部分。Class文件中除了有类的版本、字 段、方法、接口等描述信息外,还有一项信息是常量池表,用于存放编译期生 成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。