Java内存区域
程序计数器
- 当前线程所执行字节码的行号指示器
- 线程私有,保证线程切换能恢复到正确的执行位置
- 线程正在执行Java方法,则记录的是正在执行的虚拟机字节码指令的地址; Native方法,则为空(undefined)
- 此内存区域是唯一一个没有规定OutOfMemoryError的区域
Java虚拟机栈
线程私有,生命周期同线程一样
描述Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧来存储局部变量表,操作数栈、动态链接、方法出口等信息
局部变量表存放编译期可知的各种基本数据类型、对象引用类型(reference类型)和returnAddress类型(指向一条字节码指令的地址)
栈上分配技术,对线程私有的对象可以分配在栈上,不需要GC介入,提高性能
通过 -Xss参数设置栈大小
如果线程所请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
如果虚拟机栈可以动态扩展、扩展时候无法申请到足够的内存,将抛出OutOfMemoryError异常
本地方法栈
为虚拟机使用到的native方法服务
Java堆
- Java内存管理中最大的一块,虚拟机启动时创建
- 主要存储对象实例和数组
- 从内存回收角度可分为新生代和老年代,新生代可分为Eden区,From Survivor区, To Survivor 区
- 通过 -Xmx 和 - Xms设置堆空间
- 如果堆中没有内存完成实例分配,且堆也无法再扩展。将抛出OutOfMemoryError
方法区(永久代)
- 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
- 永久代是HotSpot虚拟机特有的概念,是对方法区的实现,别的JVM没有永久代的概念
- 通过 -XX: permSize 和 -XX:MaxPermSize设置大小
- 在JDK8中,JDK8的HotSpot VM已经是以前的HotSpot VM与JRockit VM的合并版,永久代替换为元空间(避免永久代OOM: PermGen问题,同时整合JRockit)
- 当方法区无法满足内存分配需求时,将抛出OutOfMemoryError
元空间
元空间是一块与堆不相连的本地内存
永久代中原来存储的字符串常量(池)、符号引用(这两个在jdk7普遍就已经将其放在堆上了)和类的静态变量现在存储在java堆中,其余的数据(类信息,JIT编译后的代码)作为元数据存储在元空间中
默认情况下,类元数据只受可用的本地内存限制,新参数(MaxMetaspaceSize)用于限制本地内存分配给类元数据的大小
元数据: 描述数据的数据
元数据可以为数据说明其元素或属性(名称、大小、数据类型、等),或其结构(长度、字段、数据列),或其相关数据(位于何处、如何联系、拥有者)
运行时常量池
- 方法区的一部分,用于存放编译期生成的各种字面量和符号引用(保存Class文件中描述的符号引用、翻译出来的直接引用)
- 动态性,运行期间也可将新的常量放入池中
- 常量池无法再申请到内存将抛出OutOfMemoryError
直接内存
- 不是虚拟机规范中定义的内存区域
- NIO中,使用Native函数库分配堆外内存,通过存储在Java堆中的directByBuffer对象作为这块内存的引用进行操作
- 动态扩展时,各内存区域超过物理内存限制,导致OOM