一丶线程私有:
-
程序计数器:
可以看做是线程执行字节码的行号指示器
如果正在执行java方法,这个计数器记录的是正在执行的虚拟机的字节码指令的地址
如果正在执行native方法,这个计数器记录的值为空(undefined)
唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域
-
Java虚拟机栈
描述的是Java方法执行的内存模型
每个方法执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出入口等信息
如果线程请求栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常
如果虚拟机栈在扩展的过程中无法申请到足够的内存,就会抛出OutOfMemory异常
-
本地方法栈
- 与虚拟机栈相同,只不过是为虚拟机使用到的Native方法服务。
二丶线程共享
-
Java堆
所有对象实例以及数组都要在堆上进行分配(并不是那么绝对)
-Xmx -Xms
堆中没有内存完成实例分配,并且堆也无法扩展时,就会抛出OutOfMemoryError异常
-
方法区(永久代)
存储加载的类信息、常量、静态常量、即时编译器编译后的代码数据
Java7及之前的版本:-XX:PermanSize Java8及之后的版本:-XX:MetaspaceSize
当方法区没法满足内存分配需求时,将抛出OutOfMemoryError异常
-
运行时常量池
是方法区的一部分
存储编译期的生成的各种字面量与符号引用,运行时也会将新的常量放入池中
常量池是方法区的一部分,当常量池无法再申请到内存时就会抛出OutOfMemoryError
-
直接内存
不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的区域
NIO引入了一种基于通道与缓冲区的I/O方式,使用native函数库直接分配堆外内存,通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作
动态扩展时会出现OutOfMemoryError异常
三丶Java版本迭代导致的内存区域发生的变化
在Java7之前,HotSpot虚拟机中将GC分代收集扩展到了方法区,使用永久代来实现了方法区。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载。但是在之后的HotSpot虚拟机实现中,逐渐开始将方法区从永久代移除。Java7中已经将运行时常量池从永久代移除,在Java 堆(Heap)中开辟了一块区域存放运行时常量池。而在Java8中,已经彻底没有了永久代,将方法区直接放在一个与堆不相连的本地内存区域,这个区域被叫做元空间。

