JVM在运行时将其内存区域划分为不同的区域,各区域承担的职责和生命周期不尽相同,有的随着JVM进程的存在(消亡)而存在(消亡),而有些则是线程私有的,生命周期与其所在线程一致。和笔者一块学习一下吧~
- 方法区(Method Area)
- Java堆(Heap)
- 虚拟机栈(VM Stack)
- 本地方法栈(Native Method Stack)
- 程序计数器(PCR)
方法区(别名:Non-Heap)
作用:存储已在VM中加载的类信息、常量、静态变量、即时编译器编译后的代码。
特征:
1、线程共享(下面提及的“堆”亦是如此)。
2、当方法区无法满足内存分配需求时,抛出OutOfMemoryError异常。
Java堆
作用:提供所有对象实例和数组的分配,几乎所有的对象实例都在此分配。但随着JIT编译器的发展和逃逸分析技术的成熟,产生了“栈上分配”和“标量替换优化技术”(参考此处了解)等,导致并非所有的对象都会分配在堆上。
特征:
1、垃圾收集器管理的主要区域,称为“GC堆”。
2、分为:老年代和新生代(细致点划分:Eden空间、From Survivor、To Survivor 空间)参考此处了解
3、和磁盘一样,Java堆只要逻辑上连续即可,在实现时,既可固定大小,亦可扩展。
4、堆中没有多余的内存完成实例分配且无法扩展时,将会抛出OutOfMemoryError异常。
5、线程共享(同上方法区)
虚拟机栈
作用: Java方法执行的内存模型,方法在执行时会创建一个栈帧(Stack Frame),用以存储局部变量表,操作数栈,动态链接、方法的出入口等,栈帧在栈中的出入栈表示方法的开始调用到结束调用。
特征:
1、线程私有,生命周期与线程一致。
2、线程请求的栈深度>JVM允许的栈深度,抛出StackOverflowError异常。
3、假设栈可动态扩展,则若扩展时无法申请到足够的内存,则抛出OutOfMemoryError异常。
本地方法栈
作用:与上面的虚拟机栈相似,虚拟机栈针对Java方法(处理Java字节码),而本地方法栈为JVM使用到的Native方法服务。
特征:与上面的虚拟机栈类似,也会抛出上述两个异常。
程序计数器
作用:当前线程所执行的字节码的行号指示器,字节码解释器工作时通过改变该计数器的值来选取下一条需要执行的字节码指令,譬如 分支、循环、跳转、异常处理、线程恢复等。
特征:
1、一个线程一个PCR,各线程之间的存储独立,即线程私有。
2、Java方法而言:记录正在执行的虚拟机字节码指令的地址;Native方法而言:计数器的值Undefined。
3、此区域是唯一的没有任何OutOfMemoryError异常的区域。