JVM内存由来
Java源文件经过编译器编译成字节码文件,字节码文件交由类加载器加载时,会存储执行期要用的数据和信息到运行时数据区,就是JVM内存。
JVM内存结构
程序计数器
- 线程私有
- 执行JAVA方法时,程序计数器保存当前需要执行的指令的地址。CPU根据程序计数器中的地址获得指令,得到指令后,程序计数器中的值加一或转移指针到下一条指令的地址。
- 执行本地方法(Native 方法)时,程序计数器中的值是空(undefined)。
- 程序计数器是JVM内存中唯一不会出现OutOfMemoryError异常的地方
虚拟机栈
- 线程私有
- 当线程执行一个方法时,随之创建一个对应的栈帧,并将其压栈。方法执行完毕后,将栈帧出栈。
- 栈帧用于存储局部变量表(包括参数)、操作数栈、动态链接、方法出口等信息。
- 异常
(1)线程请求的栈深度大于虚拟机允许的栈深度时,发生StackOverflow异常。
(2)虚拟机栈空间可以动态扩展,当动态扩展无法申请到足够空间时,发生OutOfMemoryError异常。
本地方法栈
- 线程私有
- 本地方法栈与虚拟机栈基本类似,区别在于本地方法栈为执行本地方法服务,虚拟机栈为执行Java方法服务。
- HotSpot虚拟机将虚拟机栈和本地方法栈合二为一
堆
- 线程共享
- HotSpot虚拟机的堆内存被分为新生代和老年代
- 对象实例及数组存储在堆中,实例引用存储在虚拟机栈中。
- 堆是可扩展的,当堆中没有内存完成实例分配且堆也无法扩展时,发生内存溢出。
方法区
- 线程共享
- 用于存储虚拟机加载的静态变量、常量、类信息、运行时常量池,类信息包括类的版本、字段、方法、接口、构造函数等描述信息,运行时常量池用于存放编译期生成的字面量和符号引用。
- JDK1.7后,JVM将字符串常量池从方法区中移出来,在JVM堆中开辟一块区域存放字符串常量池。
- JDK1.7及之前,HotSpot虚拟机以永久代来实现方法区。
- JDK1.8后,取消永久代,改为元空间。元空间使用本地内存,而不在虚拟机中
- 当方法区无法申请到内存时,发生OutOfMemoryError异常。