1. 程序计数器(线程私有)
当前线程所执行的字节码的行号指示器,占用空间小。
线程执行Java方法:计数器记录正在执行的虚拟机字节码指令的地址;
线程执行Native方法:计数器为空。
此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
2 虚拟机栈(线程私有)
每个方法在执行的同时会创建一个栈帧用于存储对于局部变量表、操作数栈、动态链接、方法出口等信息,然后放入栈中。每个时刻正在执行的当前方法就是虚拟机栈顶的栈帧。方法的执行就是对应着栈帧在虚拟机栈中入栈和出栈的过程。
本区域的两种异常情况:
① StackOverflowError异常:线程请求的栈深度大于虚拟机所允许的深度;
② OutOfMemoryError异常:虚拟机栈动态扩展到无法申请到足够的内存。
3 本地方法栈(线程私有)
与虚拟机栈发挥的作用相似,JVM简单的动态链接并直接调用nativa方法;
二者区别是:虚拟机栈为虚拟机执行Java方法(字节码0)服务;
本地方法栈为虚拟机使用到的Native方法服务。
本区域的两种异常情况:
① StackOverflowError异常:线程请求的栈深度大于虚拟机所允许的深度;
② OutOfMemoryError异常:本地方法栈动态扩展到无法申请到足够的内存。
4 堆(线程共享)
Java虚拟机锁管理内存中最大的一块,所有线程共享的一块区域;
垃圾收集器管理的主要区域,也被称作GC堆;
可用以下参数调整:
-Xms: 堆的最小值;
-Xmx: 堆的最大值;
-Xmn: 新生代的大小;
-XX:NewSize: 新生代最小值;
-XX:MaxNewSize: 新生代最大值;
本区域的异常情况:
① OutOfMemoryError异常:堆无法申请到足够的内存。
5 方法区/永久代(线程共享),别名Non-Heap
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
运行时常量池属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用。
本区域的异常情况:
① OutOfMemoryError异常:方法区无法满足内存分配需求。
可用以下参数调整:
jdk1.7及以前:-XX:PermSize;-XX:MaxPermSize;
jdk1.8以后:-XX:MetaspaceSize; -XX:MaxMetaspaceSize
jdk1.8以后大小就只受本机总内存的限制
如:-XX:MaxMetaspaceSize=3M
6 直接内存(线程共享)
不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。如果使用了NIO(New Input/Output),本区域会被频繁的使用。在Java堆中可以用DirectByteBuffer对象作为这块内存的引用进行操作。
这块内存不受java堆大小限制,但受本机总内存的限制,可以通过-XX:MaxDirectMemorySize来设置(默认与堆内存最大值一样),所以也会出现OOM异常。
各个版本内存区域的变化
线程的角度看内存
深入辨析堆和栈
未完待续...