程序计数器
当前线程所执行字节码的行号指示器。
字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器来完成。
线程私有,没有OOM
如果线程正在执行的是一个Java方法,这个计数器记录的正在执行的虚拟机字节码指令的地址;
如果正在执行的是Native方法,这个计数器值为空。
Java虚拟机栈
每个方法执行时都会创建一个栈帧。
栈帧结构:
- 局部变量表
- 基本数据类型(boolean,byte,char,short,int,float,long,duble)
- 对象引用类型(对象地址指针,对象句柄)
- returnAddress类型(指向一条字节码指令的地址)
- 操作数栈
- 动态链接
- 方法出口
线程私有,long和double占2个局部变量空间Slot
如果线程请求的栈深度大于虚拟机所允许的深度----->StackOverflowError
如果虚拟机栈可以动态扩展且扩展时无法申请到足够的内存----->OutOfMemoryError
本地方法栈
线程私有
如果线程请求的栈深度大于虚拟机所允许的深度----->StackOverflowError
如果虚拟机栈可以动态扩展且扩展时无法申请到足够的内存----->OutOfMemoryError
Java堆
线程共享
几乎所有的对象实例以及数组都在堆上分配内存。
即时编译,逃逸分析,栈上分配,标量替换
内存分配的角度,会将堆划分成多个线程私有的分配缓冲区
内存回收的角度,会将堆划分成新生代老年代
如果堆上没有内存完成实例分配,并且堆也无法再扩展时----->OutOfMemoryError
方法区
线程共享
存储内容:
- 类信息
- 常量
- 静态变量
- 即时编译器编译后的代码
String.intern()
内存回收目标:主要是针对常量池的回收和对类型的卸载
当方法区无法满足内存分配需求时----->OutOfMemoryError
运行时常量池
方法区的一部分。用于存放Class在编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池
具备动态性:并非预置入Class文件中常量池的内容才能进入运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员用的比较多的便是String.intern()方法
当常量池无法再申请到内存时----->OutOfMemoryError
直接内存
不属于运行时数据区域,但是可能发生OutOfMemoryError。
不受Java堆大小限制,但受本机总内存限制,当各个内存区域综合大于物理内存限制时-->OutOfMemoryError。