JVM内存区域

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异常:堆无法申请到足够的内存。

方法区/永久代(线程共享),别名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异常。

各个版本内存区域的变化

 

 

线程的角度看内存

深入辨析堆和栈

 

未完待续...

原文地址:https://www.cnblogs.com/xuzhuteng/p/14983681.html