Java内存模型图
程序计数器
- 是一块较小的内存空间, 用来指示当前线程正在执行的Java字节码位置. 如果正在执行Java方法, 则计数器记录的是当前字节码的地址, 如果正在执行本地方法, 则计数器为空.
- 线程私有, 所以不会出现线程安全问题.
- 此区域是唯一一个在<<Java虚拟机规范>>中没有规定任何OutOfMemoryError的区域
虚拟机栈
- 生命周期和线程保持一致, 每个线程都会分配一块栈空间, 这也解释了为啥不要频繁地创建线程的原因, 而是尽量复用线程, 创建线程的过程牵涉到虚拟机栈的内存分配, 空间不足则会导致OutOfMemoryError, 销毁线程又涉及到栈内存的回收 , 出现不必要的垃圾回收.
- 栈空间是每个线程私有的, 执行的方法区的代码大多数情况下是线程安全的(代码逃逸除外.
- 当执行Java代码的时候, 会同步创建一个栈帧, 用来存储局部变量表, 操作数栈, 方法出口等信息
- 如果线程请求的栈深度大于Java虚拟机规范的深度, 抛出*Error. 如果Java虚拟机可以动态扩展, 当栈无法申请到足够的内存时, 出现OOM.
本地方法栈
- 与虚拟机栈类似, 只不过是执行本地方法.
- 线程私有.
- 和虚拟机栈一样, 同样会出现OOM和SOF.
堆
- 虚拟机所管理的内存中最大的一块, 在虚拟机启动时创建, 所有的对象实例和数组都在堆上创建.
- 大小一般是可扩展的.如-Xmx 1000m , 表示最大堆内存分配为1000MB, -Xms 10m 表示最小堆内存为10MB
- 当堆中没有内存完成分配时, 会出现OOM
方法区
- 存放已经被虚拟机加载的类型信息, 常量, 静态变量, 热点代码
- 线程共享, 注意线程安全问题
- jdk6以后就开始使用本地内存来实现方法区
- 当无法申请到合适的内存时, 会出现OOM
运行时常量池
- 存放class文件中的常量池的内容, 包含编译时期生成的各种字面量和符号引用
- 运行期间新的常量, 如String的intern方法
直接内存
- 不是Java运行时数据区的一部分, Java程序仍可以使用这部分内存
- 内存区域总和超过物理内存大小时, 会出现OOM.