运行时数据区
-
方法区
- Method Area,用于存储已被虚拟机加载的类信息(、、)、常量、静态变量、即时编译后的代码等数据
- 线程公用
- 类信息
- 类型信息:类class、接口interface、注解annotation、枚举enum
- 域Field信息:字段名称、字段类型、字段修饰符
- 方法method信息:方法名称、方法返回值类型、参数数量和类型、修饰符、方法的字节码、操作数栈、局部变量表以及大小、异常表
-
Java堆
-
Java Heap,Java虚拟机中内存最大的一块,是线程共享的,几乎所有的对象实例都会在这里进行分配。
-
当一个对象进过逃逸分析,确定对象的作用域只在方法内,不会被其它方法获取到时,会使用标量替换,将对象分解成一个个的属性值,直接分配到栈上,等方法执行完成,栈帧销毁时,顺便将对象一块销毁,减少垃圾回收的工作量。
-
对于每一个线程,在Java堆上都有一块私有的内存区域,叫做TLAB(Thread Local Allocation Buffer)线程本地分配缓存,用于新生成对象的分配。因为是线程私有,不用加锁,加快对象的生成。该区域的大小是JVM运行时计算得到的,适合小对象的存放。生成的对象过大,TLAB存储不小时,还是需要去共有区域进行内存的分配。
-
线程公用
-
存放的对象实例
- 对象实例
- 类初始化生成的对象
- 基本数据类型的数据也是对象实例
- 字符串常量池
- JDK6以及之前存放在方法区,JDK7之后存储在堆中
- 字符串常量池中存放的是String对象的直接引用,对象还是放在常量池区域外的堆中。
- 静态变量
- JDK7时从方法区迁移至堆中
- 对象实例
-
-
虚拟机栈
- Java Virtual Machine Stacks,用于存储方法栈帧,每个栈帧中存放方法需要的局部变量表、操作数栈、动态链接、方法出口等信息。
- 线程私有
- 如果线程请求的栈深度大于虚拟机规定的栈深度,会抛出StackOverFlowError。
- 如果栈容量可以动态扩展,扩展时如果申请不到内容,会抛出OutOfMemoryError。
-
本地方法栈
- Native Method Stack,与虚拟机栈的作用是一样的,是为本地(Native)方法服务的。
- 线程私有
-
程序计数器
- Program Counter Register,用于标记吓一条要执行的字节码的位置,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器完成。
- 线程私有,是唯一一个不会存在溢出的区域