JVM——内存区域

2018-09-07  本文已影响0人  Samuel_Tom

程序计数器

程序计数器是当前线程所执行的字节码的行号指示器,通过改变计数器的值来执行下一条字节码指令,程序代码的分支、循环、跳转等基础功能都需要依赖程序计数器来实现。每条线程都有一个独立的程序计数器,各线程间的计数器互不影响,该区域是线程私有的(该内存区域是唯一一个在Java虚拟机规范中没有任何OOM情况的区域)。

Java虚拟机栈

在每个Java方法执行前都会创建一个虚拟机栈,主要用于存储局部变量表、操作数栈、方法返回地址等信息;局部变量表主要包含各种基本数据类型(八大基础数据类型)、对象引用、方法参数、方法内局部变量等,局部变量表所需的内存空间在编译期间已经完成分配,该区域是线程私有的,它的生命周期与线程相同。在Java虚拟机规范中,对这个区域规定了两种异常情况:
(1)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;
(2)如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemory异常;

Java栈中最主要的组成部分是栈帧,一个栈帧代表一个方法的执行,每个方法从调用到执行完成就对应一个栈帧在虚拟机栈中入栈到出栈的过程。也就说当方法A调用方法B的时候,方法B就会被压入栈中,当方法B调用完成并返回到方法A时,B就从栈中出栈。栈帧中存储了Java方法调用所需要的全部数据:局部变量表、栈操作数、动态链接、方法出口。

本地方法栈

跟虚拟机栈差不多,唯一的区别是虚拟机栈为虚拟机执行Java方法服务,本地方法栈为虚拟机执行Native方法服务。

Java堆

Java堆是最大的一块内存区域,主要存放所有对象实例数组,所以也是垃圾收集器管理的主要区域,不要求物理上是连续的内存地址,堆是在程序运行时动态分配内存大小的,该区域是线程共享的。

方法区

方法区用于存储已经被虚拟机加载的类信息常量静态变量、即时编译器编译后的代码等数据,该区域是线程共享的。

补充

在JVM虚拟机中,栈中的对象引用如何去定位堆中已经分配的对象实例数据与对象类型数据,有两种方法:
句柄访问:如果采用句柄访问的形式,会在堆中划分一块内存区域来作为句柄池,句柄池中包含了对象实例数据与对象类型数据的具体地址信息,而栈中的对象引用则保存了对象的句柄地址;优势是比较稳定,当堆中对象移动时只需改变句柄的地址,而不用改变对象引用的指针地址。
直接指针:栈中的对象引用直接保存对象的地址,直接访问堆中的对象实例数据与对象类型数据;优势是访问速度快,节省了一次指针定位的时间开销。

参考

《深入理解Java虚拟机》第2版 第2章 Java内存区域与内存溢出异常

上一篇下一篇

猜你喜欢

热点阅读