一、运行时数据区域
JVM在执行java程序的过程中会把他所管理的内存划分为若干个不同的数据区域。这些区域有各自的创建和销毁的时间,这些区域可分为线程私有和共有两类,
线程私有的有:
程序计数器、
java虚拟机栈、
本地方法栈;
线程公有的有:
堆、
方法区。如图所示:
1、程序计数器(线程私有)
也就是
字节码的行号指示器(
模拟的是CPU的程序计数器),
指示
当前进程
所要执行的字节码(而不是下一条),这个指令将交给
字节码解释器去完成解释功能。
因为要保证线程切换后能恢复到正确的执行位置,每条线程都需要有个独立的程序技术器,各条程序计数器之前互不影响,独立存储。所以他是“
线程私有的”。
如果一个线程正在执行一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地方法,这个计数器值为null。
2、java虚拟机栈(线程私有)
描述的是
java方法执行的内存模型:
栈中存储的是一个一个的
栈帧
(
每个方法在执行的同时都会创建一个栈帧),而一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
栈帧:
存储局部变量表(方法中的局部变量)、操作数栈、动态链接、方法出口等信息。
1、局部变量表
用来存储方法参数和方法内部定义的局部变量。
【包括:8种基本数据类型、对象引用(eference)和returnAddress()】。局部变量表的容量是以
变量槽
为最小单位的。
其中long和double会占用两个局部变量空间,其余的只占1个空间
。
局部变量表所需要的内存空间在编译期已经完成分配
。局部变量表中的变量使用之前必须赋予初始值,不想类变量有两次赋初始值的过程(一次在准备阶段,赋予系统初始值;一次在初始化阶段,赋予程序员定义的值)
2、操作数栈
操作数栈的每一个元素可以是任意Java数据类型,32位数据类型所占的栈容量为1字宽,64位数据类型所占的栈容量为2字宽。对于32位虚拟机来说,一个”字宽“占4个字节,对于64位虚拟机来说,一个”字宽“占8个字节。
当一个方法刚刚执行的时候,这个方法的操作数栈是空的,在方法执行的过程中,会有各种字节码指向操作数栈中写入和提取值
另外,在概念模型中,两个栈帧作为虚拟机栈的元素,相互之间是完全独立的,但是大多数虚拟机的实现里都会作一些优化处理,令两个栈帧出现一部分重叠。
让下栈帧的部分操作数栈与上面栈帧的部分局部变量表重叠在一起
,这样在进行方法调用返回时就可以共用一部分数据,而无须进行额外的参数复制传递了,重叠过程如下图:
3、动态链接
每个栈帧都包含一个指向运行时常量池
(方法区中的一部分空间,用来存储各种字面量和符号的引用)