Java内存模型之运行时数据区域

 2019-12-10 16:01  阅读(911)
文章分类:Java Core

Java虚拟机会开辟一块内存区域,单独给Java程序使用,这块内存区域又可以分为以下多个部分,如下图1:

20191210001499\_1.png

图1

以下表格列出了这些区域的一些特点与区别,如表1:

20191210001499\_2.png

表1

作用解释:

程序计算器:用来存贮线程执行当前运行java程序的指令的地址字节码,也就是returnAddress类型。一个线程一个程序计数器;

如若当前线程执行的是java方法,则存储指令地址;如若当前线程执行的是Native方法,则存贮的是Undefined;

Java虚拟机栈:用于存储每个线程所执行的方法的栈帧。每个方法被执行的时候,会同时创建一个栈帧,入栈到Java虚拟机栈;

方法执行完毕,则会出栈该栈帧。栈帧中会保存一系列方法中相关的数据,包括局部变量表,操作数栈,动态链

接,方法出口等信息;

栈的大小可以由参数-Xss控制;

栈帧:方法的调用与完毕,伴随着栈帧的入栈和出栈;栈帧的大小,主要是局部变量表的大小和操作数栈的深度,在编译器就会决

定;如图2:

20191210001499\_3.png

图2 栈帧图

局部变量表:用于存放java虚拟机中10种类型数据(byte,short,int,long,float,double,char,boolean,reference,

returnAddress);8个基本数据类型数据值都直接存储在栈内,其余两种只是存储引用;内部以slot

为单位,除了long,double64位长度需要存储2个slot外,其余都只需要1个slot存储;局部变量表的大

小编译的时候固定;

局部变量表中的slot可以复用,如果某个局部变量生命周期结束了,该slot就可以被该栈帧中下一个定义的局部变量占

用;

局部变量表中的变量在类加载的时候没有准备阶段,没有初始值阶段,因此必须声明的时候赋值,不然编译不通过;

局部变量表的第一个slot存放的是该方法所属对象的引用;可以通过this关键字来调用;

操作数栈: 用于方法内部数据运算的存储空间,一次运算的数据往往来源于栈顶的两个元素,出栈运算完毕后入栈结果;因此,

在编译阶段和类加载的类校验阶段,必须严格验证指令的数据类型与操作数栈的数据对应匹配;

注:当方法调用的时候,如A调用B,一般会把A当前的PC计数器的位置保存在B的栈帧中,当B返回出栈的时候,会让PC计数器指

向B栈帧保存的这个地址;

本地方法栈:与java虚拟机栈功能一样,只不过它服务与Native方法;

Java堆:存放对象实例的区域,GC回收器主要作用的地方;堆的大小可以由参数-XMX,-XMS控制;

方法区:用于存放一些关于类的信息,一些类的变量(非方法实例变量,局部变量),即时编译代码等,其中有一块静态区域,专门用来存放静态变

量和静态代码块;还有方法信息,包括方法表,还有方法体中编译后的字节指令码;它可以选择是否实现垃圾收集;一般垃圾收集不在这

个区域,因此也被称为“永久代”;

运行时常量池(存在于方法区中):存放编译期产生的各种字面量和符号引用;

直接内存:是处于堆外的内存,被java直接调用,称为直接内存;

关于内存溢出与栈溢出:

StackOverflowError:在虚拟机初始化的时候,会给栈分配固定的大小,当线程请求的栈深度大于栈的大小时候,就会抛出该异

常;

OutOfMemoryError:栈,堆通常可以动态扩展,即在栈深度不够用的时候,可以申请扩展空间大小;当无法再申请到更多的空

间,而又不能满足当前栈或堆空间资源需求的时候,就抛出该异常;

**举例:**对于一个语句如 Object object = new Object();这样的对象创建,在内存中有两种方案的内存调用模型,一种为句柄式,一种为直接引用式;

对于直接引用式来讲,如图3:

20191210001499\_4.png

图3

对于句柄引用来讲,如图4:

20191210001499\_5.png

图4
在堆中,对于对象中引用的基本类型数据,基本上会直接存储在堆中,对于如String等引用类型,堆中存储引用,然后值在常量池中。

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Java内存模型之运行时数据区域

相关推荐