运行时数据区域
程序计数器
- 每个线程都拥有自己独立的程序计数器,属于线程私有的内存区域
- 当前执行的是Java方法,则计数器记录的是正在执行的虚拟机字节码指令地
- 当执行的是native方法时,则这个计数器为空
- 不会抛出异常
Java虚拟机栈
- 线程私有,生命周期与线程相同
- 每个方法执行的同时会创建一个栈帧,用于存储操作局部变量、操作数栈等,每个方法的执行过程实际上是栈帧在虚拟机栈中入栈出栈的过程
- 当线程请求的栈深度大于虚拟机规定的最大值时,抛出StackOverflowError异常
- 当虚拟机栈动态申请内存无法满足时,抛出OutOfMemoryError异常
本地方法栈
- 线程私有区域
- 与Java虚拟机栈类似,Java虚拟机栈作用于Java方法,而本地方法栈作用于Native方法
堆空间
- 线程共享区域
- 用于存放对象实例,所有对象实例和数组都要在堆上分配
- 堆空间分为Eden区、From Survivor区、To Survivor区
- 当堆空间动态申请内存无法满足时,抛出OutOfMemoryError异常
方法区
- 线程共享区域
- 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码数据等
- 当方法区无法申请内存时,抛出OutOfMemoryError异常
运行时常量池
- 属于方法区的一部分
直接内存
- NIO可以使用native函数直接分配堆外内存,然后通过存储在堆内的DirectByteBuffer对象作为这块内存的引用
- 本机直接内存不受Java堆大小的控制,但如果直接内存+虚拟机分配的内存总数大于机器物理内存时,会抛出抛出OutOfMemoryError异常异常
对象的访问方式
通过句柄访问
Java堆中有相关的句柄池,java栈reference保存着句柄池中具体句柄的地址,句柄中保存有指向堆中对象实例的指针和到对象类型数据的指针
image直接使用指针访问
Java栈reference中保存堆中对象实例的指针,对象实例中存有到对象类型数据的指针
image
句柄访问和指针访问对比
- 句柄访问的好处是Java栈reference中保存的是句柄的地址,当对象被移动时,只会改变句柄中指向堆中对象实例的指针,而reference本身保存的句柄地址不需要修改
- 直接指针访问的好处是速度更快,节省了一次指针定位的时间开销,HotSpot虚拟机采用直接指针访问方式
网友评论