2.Java内存区域与内存溢出异常
2.1 运行时数据区域
2.1.1 程序计数器
- 程序计数器(program counter register),当前线程所执行的字节码的行号指示器;
- 字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令;
- 实现分支、循环、跳转、异常处理、线程恢复等功能
- 线程私有
- 如果线程正在执行java方法,计数器记录的是正在执行的虚拟机字节码指令的地址。
2.1.2 Java虚拟机栈
- 线程私有;
- 描述Java方法执行的线程内存模型: 执行方法时创建一个栈帧(stack frame)存储局部变量表,操作数栈,动态连接,方法出口等信息;
- 每一个方法被调用到执行完毕的过程,对应一个栈帧在虚拟机栈中从入栈到出栈的过程;
- 局部变量表
- 编译期可知的JVM基本数据类型(Boolean byte char short int float long double)
- 对象引用 reference类型
- returnAddress类型
- 异常
- 线程请求的栈深大于JVM许可的深度 --> StackOverflowError
- 栈扩展无法申请到足够内存 --> OutOfMemoryError(OOM)
2.1.3 本地方法栈(Native Method Stacks)
- 与虚拟机栈作用类似,但是为本地方法服务;
2.1.4 Java堆
- 存放对象实例;
- Java堆是JVM管理内存中的最大一块;所有线程共享的一块儿内存区域;
- Java堆是垃圾收集器管理的内存区域(GC堆,garbage collected heap);
- 划分出线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)提升对象分配效率;
- Java堆处于物理上的不连续的内存空间,但是逻辑上认为连续。
2.1.5 方法区
- 线程共享
- 存储已被虚拟机加载的数据
- 类型信息
- 常量,静态变量
- 即时编译器编译后的代码缓存
- 运行时常量池 Runtime Constant Pool
- 隶属于方法区,存放编译期生成的各种字面量和符号引用
- 类加载后从class文件中读入常量池表
- 动态性,运行期间常量存入
2.1.6 直接内存
- NIO类, Native函数库直接分配堆外内存,通过存储在Java堆内的DirectByteBuffer对象作为这块内存的引用进行操作。