JVM虚拟机内存划分
JVM内存结构划分图
运行时数据区
程序计数器
当前线程所执行的字节码的行号指示器
- 线程私有
- 线程执行Java方法,记录正在执行的虚拟机字节码指令地址
- 线程执行Native方法,则计数器值为空
- 此内存区域是Java虚拟机规范中唯一一个没有规定任何OutOfMemoryError情况的区域
Java虚拟机栈
虚拟机栈描述Java方法执行的内存模型
- Java虚拟机栈内存私有,生命周期与线程相同
- 每个方法执行会创建栈帧,存储局部变量表、操作数栈、动态链接、方法出口等信息
- 栈帧局部变量表存放了编译期可预知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用、returnAddress类型(指向了一条字节码指令的地址)
- 其中64位长度的long和double类型占用2个局部变量空间(Slot),其它占用一个。局部变量表所需空间在编译器分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是确定的
- 线程请求栈深度大于虚拟机栈所允许深度抛出StackOverflowError异常
- 若虚拟机栈可动态扩展又无法申请到足够内存抛出OutOfMemoryError异常
本地方法栈
与虚拟机方法栈的区别:
虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务
本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常
Java堆
Java堆是虚拟机管理的内存最大一块区域
- 所有线程共享
- 存放对象实例,几乎所有对象实例与数组都在这里分配内存
- 是垃圾收集器管理的主要区域,常称GC堆
- Java堆可以处于物理不连续内存,逻辑连续即可
- 虚拟机栈大小可以通过参数-Xmx和-Xms控制
- 内存不足会抛出OutOfMemoryError异常
方法区
用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码数据
- 各个线程共享的内存区域,别名Non-Heap(非堆)
- 当方法区内存无法满足分配抛出OutOfMemory异常
- 垃圾收集在这个区域很少出现
运行时常量池
- 运行时常量池(Runtime Constant Pool)是方法区的一部分,Class文件除了有类的版本、字段、方法、接口等描述信息外,还有一项是常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放
- 运行时常量池是方法区的一部分,受到内存方法区的限制,内存不足分配会抛出OutOfMemoryError异常
直接内存
不属于虚拟机运行时数据区,也不是Java虚拟机规范中定义的内存区域
- NIO缓冲区使用Native函数库直接分配堆外内存,通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作
- 受物理内存大小限制,内存不够 分配会抛出OutOfMemoryError异常