JVM内存区域的划分

JVM在执行程序的过程中把它管理的内存划分为若干个不同的区域,这些区域各有各的用处,一般来说,JVM管理的内存包含以下几个内存区域:

在这里插入图片描述
这些区域有线程私有的,也有线程共享的,那么什么是线程私有?

由于Java是多线程是通过线程之间的相互切换以及分配处理机时间的方式实现的,所以每一时刻,一个处理器只会执行一个线程中的一条指令,因此为了线程切换后恢复到正常执行位置,每个线程都有独立的计数器,各计数器之间互不影响,独立存储,我们把这一类内存区域成为是线程私有区域。

程序计数器(线程私有)

程序计数器记录的是当前线程所执行的字节码的行号指示器,如果当前线程执行的是Java方法,那么程序计数器里记录的是正在执行的虚拟机字节码指令的地址,而如果当前线程执行的是一个本地方法,那么程序计数器为空,由于程序计数器里只存放当前线程所执行的字节码的指令地址,所以不会出现OOM的情况。

Java虚拟机栈(线程私有)

虚拟机栈描述的是Java方法执行的内存模型,每个方法再执行的同时都会创建一个栈帧,用于存储局部变量表,操作数、动态链接、方法出口等信息,每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出栈,生命周期和线程相同。

我们平时所说的栈区域,实际上指的是Java虚拟机栈中的局部变量表的区域。

局部变量表

局部变量表:存放的是编译器可知的各种基本数据类型(8种基本数据类型),对象引用。局部变量表所需的内存分配是在编译器就已经完成分配的,这个方法需要在帧中分配多大的内存空间完全是确定的,运行期间是不会改变局部变量表的大小的。
此区域会产生两种异常:

1.如果线程请求的栈深度大于虚拟机所允许的栈深度(-Xss设置栈容量),将会抛出StackOverFlowError异常。
2.虚拟机在动态扩展时无法申请到足够的内存,会抛出OOM(OutOfMemoryError)异常。

本地方法栈(线程私有)

本地方法栈与虚拟机栈的作用完全一样,他俩的区别无非是本地方法栈为虚拟机使用的Native方法服务,而虚拟机栈为JVM执行的Java方法服务。
在HotSpot虚拟机中,本地方法栈与虚拟机栈是同一块内存区域。

Java堆(线程共享)

Java堆是JVM管理的最大的一块内存区域了,也是一个线程共享的区域,在JVM规范中写到所有的对象以及数组都要在堆上分配。Java堆也是垃圾回收器管理的主要区域,通常也称作是GC堆,根据JVM规范规定的内容,Java堆可以处于物理上不连续的内存空间中,Java堆在主流的虚拟机上都是可扩展的(-Xmx设置最大值,-Xms设置最小值)

如果在堆中没有足够的内存完成实例分配或者堆也无法拓展时,就会出现OOM。

方法区(线程共享)

方法区与Java堆一样是各个线程共享的区域,它用于存储已被虚拟机加载的类信息,常量和静态变量、即时编译器编译后的代码数据,在JDK8以前的HotSpot虚拟机中,方法区也被称为"永久代"(JDK8已经被元空间取
代)。永久代并不意味着数据进入方法区就永久存在,此区域的内存回收主要是针对常量池的回收以及对类型的卸载。
JVM规定,当方法去无法满足内存分配需求时,就是出现OOM。

运行时常量区

运行时常量区是方法区的一部分,存放字面量和符号引用。

字面量:字符串(JDK1.7以后移动到堆中)、final常量、基本类型的值
符号引用:类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章