运行时数据区域
Java虚拟机在执行就Java程序的时候会把它所管理的内存分为多个区域,有些区域随着Java虚拟机进程启动而一直存在,有些区域则是依赖用户线程的启动和结束而建立销毁。根据《Java虚拟机规范》,Java虚拟机管理的运行时区域如下图:
一.程序计数器
- 线程私有内存
- 是当前线程所执行的字节码的行号指示器
- 执行Java方法,计数器记录的是正在执行虚拟机字节码指令地址
- 执行本地方法,计数器的值则为空(Undefined)
- 唯一一个没有规定任何OOM的区域
说明:对于Java方法程序计数器中存储的是线程对应正在执行的虚拟机字节码指令的地址,本地方法存储的是Undefined;Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现,在同一时刻、同一个处理器(一个内核)都会执行一个线程中的指令;每次线程切换只会修改程序计数器的中当前线程对应的值。
二.虚拟机栈
- 线程私有
- 随着线程的启动而创建,线程的销毁而销毁
- 每个方法执行的时候都会创建一个自己的栈帧;栈帧中存放的是** 局部变量表、操作数栈、动态链接、方发出口等信息 。**
- 局部变量表:存放了在编译期可知的Java虚拟机的基本数据类型(byte、boolean、char、short、int、long、float、double),对象引用以及returnAddress类型;
这些数据类型在局部变量表中以局部变量槽(Slot)来表示,其中64位的长度的long及double会占用两个槽 ;其余的类型只占用一个槽;局部变量表所需要的内存空间实在编译器决定的。
如果线程请求栈的深度超过虚拟机所允许的最大深度,会报StackOverflowError异常;如果虚拟机栈允许动态扩容(HotSpot虚拟机不允许动态扩容),如果线程申请空间是失败则会报OOM异常。
三.本地方方法栈
与虚拟机栈作用相似,不同在与虚拟机栈是执行Java方法,本地方法栈执行的是本地方法(HotSpot虚拟机是将虚拟机栈与本地方法栈合二为一 )。
也会报StackOverFlowError与OOM
四. Java堆
- 是虚拟机管理的中内存最大的一块;
- 所有线程共享,虚拟机启动的时候创建;
- 存放对象实例及数组
- 是垃圾收集器管理的一个内存区域
- 分为新生代以及老年代
新生代: 包含Eden区、From Survivor、To Survivor区
- Java堆可以按照需求来扩展大小
可以通过-Xmx :最大堆内存;及-Xms :最小堆内存来设置堆大小
- 不连续的内存空间
注意:如果堆中没有内存来完成实例分配并且堆也无法拓展,则会抛OOM
五. 方法区 也叫Meta-space
- 多线程共享
- 用于存储已被虚拟机加载的类型信息、常量、静态变量、及时编译器编译后的代码缓存等数据
- 一般不会被垃圾回收,垃圾回收器在这个区域主要是针对常量池的回收和对类型的卸载。
如果方法区无法满足新的内存分配需求是将抛出OOM