JAVA运行时内存模型
JAVA运行时内存模型
对于部分Java程序员来说,Java内存分为堆和栈,这其实是非常粗略的一种划分,这里的堆对应内存模型中Java堆,栈对应内存模型中虚拟机栈,这是不全面的认识。实际上,运行时内存模型有五大区域,分为线程私有
和线程共享
两大类。其中线程私有的数据区包含程序计数器
、虚拟机栈
、本地方法栈
,线程共享的数据区包含堆
、方法区
,注意在方法区中有一个常量池
。
线程私有
-
程序计数器:
记录正在执行的字节码地址,每个线程都有自己的计数器,是私有内存空间。
-
虚拟机栈:
就是通常说的栈内存,方法执行的位置,每个方法执行时会在虚拟机栈中创建栈帧(不包含Native方法),方法执行过程,对应虚拟机栈的入栈到出栈的过程。
- 栈帧是用来支持虚拟机进行方法执行的数据结构,栈帧包含:
- 局部变量表:存放方法参数和方法内部定义的局部变量,以slot为最小单位。
- 操作数栈:虚拟机把操作数栈作为它的工作区,大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。
- 动态连接:运行时常量池中该栈帧所属方法的引用。
- 方法返回地址:正常退出,执行引擎遇到的方法返回的字节码,将返回值传递给调用者。异常退出,并且未捕获异常,那将不会有任何返回值。
- 额外附加信息:规范没有明确规定,由具体虚拟机实现。
- 栈帧是用来支持虚拟机进行方法执行的数据结构,栈帧包含:
-
本地方法栈:
虚拟机执行Native方法的内存区域,某些虚拟机的实现直接把本地方法栈和虚拟机栈合二为一,比如Sun HotSpot虚拟机。
线程共享
-
堆:
分配对象的内存区域,是Java虚拟机专利的最大的一块内存,也是GC的主战场,里卖弄存放的几乎多有的对象实例和数据数据,(JIT编译器有栈上分配、标量替换等优化技术的实现导致部分对象实例数据不存在Java堆中,而是存在栈内存中)。
-
从内存回收的角度,为了更快的回收内存,Java堆被分为新生代和老年代。
-
从内存分配的角度,为了更快的分配内存,Java堆可以划分出线程私有的分配缓冲区(Thread Local Alloction Buffer,TLAB)。
对象实例的结构:对象头、实例数据、填充数据;注意,堆上分配内存是兵发进行的,虚拟机采用CAS加失败重试保证原子性操作,或者采用每个线程预先分配TLAB内存。
-
-
方法区:
存放虚拟机加载的类信息、常量、静态变量、编译器编译后的字节码数据。
-
常量池:
常量池是方法区的一部分,存放编译器生成的各种字面量和符号引用;另外运行期也可将新的常量加入常量池中。
- 字面量:与Java语言中常量概念相近,包含文本字符串、声明位final的常量值等。
- 符号引用:编译语言层面的概念,包含以下三类:
- 类和接口的全限名。
- 字段的名称和描述符。
- 方法名称和描述符。