天天看点

java内存结构由哪些部分_Java内存结构

一、Java运行时数据区

JVM在执行Java程序的过程中会把它所管理的区域划分为多个不同的数据区域。每个区域都有不同的用途,以及创建和销毁时间。有的区域会随着虚拟机进程的启动而存在,有些区域则依赖用于线程的启动和线程的启动和结束和创建或销毁。

根据JVM规范,JVM所管理的内存分为以下几个运行时数据区域:

java内存结构由哪些部分_Java内存结构

1.程序计数器(Program Counter Register)

程序计数器中存储着当前线程所执行的指令的位置。

由于JVM的多线程是基于处理器分配时间片的方式轮流执行的,每一个确定的时刻,一个处理器只能执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每个线程都有一个独立的程序计数器,各线程之间的计数器是彼此不干扰的。

执行本地方法时,PC的值为undefined

2.Java虚拟机栈

Java虚拟机栈描述的是方法执行的内存模型:每个方法在执行时会创建一个栈帧用于存储临时变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

3.本地方法栈

本地方法栈与Java虚拟机栈的作用比较类似,区别是Java虚拟机栈执行的是Java方法,而本地方法栈执行的是本地方法。

JVM规范对本地方法栈所使用的语言、使用方式与数据结构并没有强制规定,因此HotSpot虚拟机将Java虚拟机栈和本地方法栈合二为一。

4.Java堆

Java堆的唯一目的就是存放对象。它是被所有线程共享的的区域,在虚拟机启动时创建。

Java堆是垃圾回收器管理的主要区域。从内存回收的角度来看,由于现在的垃圾回收器都采用的是隔代收集算法,所以Java堆可以分为新生代和老年代。其中新生代又分为了Eden区,Survivor区(from和to)。

5.方法区

方法区与Java堆一样,是线程共享的区域,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。

运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。

常量池:在jdk1.6之前,这块区间属于永久区,但是在jdk1.7以后,被移到了堆中进行管理。

6.直接内存

直接内存并不是JVM运行时数据区的一部分,JDK引入的NIO可以使用DirectByteBuffer进行直接堆外内存分配,以提高效率。

二、JDK8中的元空间

面试题

1.jvm运行时数据区的划分?各区域的作用?

2.哪些区域会发生OOM?

除了程序计数器是唯一一个在Java虚拟机规范中没有规定OutOfMemoryError的区域。

①.Java虚拟机栈:

在Java虚拟机规范中,对这个区域规定了两种异常状况:

StackOverError:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverError异常;

OutOfMemoryError:通常虚拟机栈可以动态扩,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

②.本地方法栈:

HotSpot虚拟机将本地方法栈和Java虚拟机栈合二为一。本地方法栈区域也会抛出StackOverError异常和OutOfMemoryError异常。

③.Java堆:

当堆中没有内存完成实例分配,并且堆也无法再扩展时,就会抛出OutOfMemoryError异常。

④.方法区:

当方法区无法满足内存分配需求时,将抛出OutOfMemory异常。

⑤.运行时常量池:

位于方法区,自然会受到方法区内存的限制。当常量池无法再申请到内存时会抛出OutOfMemory异常。

⑥.直接内存:

直接内存并不是JVM运行时数据区的一部分。但仍可能导致OutOfMemory异常出现。

本机直接内存的分配不会受到Java堆大小的限制,但是,既然是内存,肯定会受到本机总内存大小的限制。