Java 虚拟机的运行时数据区由程序计数器、java 虚拟机栈、本地办法栈、Java 堆、办法区、运行时常量池以及间接内存形成。形成图如下:
程序计数器
程序计数器是一块较小的内存空间,能够看作是以后线程所执行的字节码行号指示器。因为 Java 虚拟机的多线程是通过线程切换并调配处理器执行工夫的形式来实现的,在任何一个确定的实可,一个处理器都只会执行一条线程中的指令。因而,为了线程切换后能复原到正确的执行地位,每条线程都须要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,咱们成这类内存区域为“线程公有内存”。
程序计数器是在 java 虚拟机标准中 惟一 一个没有规定任何 OutOfMemoryError 状况的区域。
Java 虚拟机栈
Java 虚拟机栈也是线程公有的,它的生命周期与线程雷同。
虚拟机栈形容的是 java 办法执行的内存模型:每个办法在执行的同时都会创立一个栈帧用于存储局部变量表、操作数栈、动静链接、办法进口等信息。每一个办法从调用直至执行实现的过程,就对应这一个栈帧在虚拟机中从入栈到出栈的过程。
虚拟机栈中的局部变量表寄存了编译期可知的各种根本数据类型(double,boolean,byte,char,short,int、long,float)、对象援用以及 returnAddress 类型。其中 64 位长度的 long 和 double 类型的数据会占用 2 个局部变量空间,其余数据类型只占用 1 个。局部变量表所需的内存空间在编译期实现调配,当进入一个办法时,这个办法须要在帧中调配多大的局部变量空间时齐全确定的,在办法运行期间不会扭转局部变量表的大小。
在 java 虚拟机标准中,对这个区域规定了两种异常情况:
- 如果线程申请的栈的深度大于虚拟机所容许的深度,将抛出 StackOverFlowError 异样;
- 如果虚拟机能够动静扩大,如果扩大时无奈申请到足够的内存,就会抛出 OutOfMemoryError 异样。
本地办法栈
本地办法栈与虚拟机栈的作用十分类似,虚拟机栈为执行 java 办法服务,本地办法栈为虚拟机中应用到的 Native 办法服务。在有的虚拟机中,比方 Sun HotSpot 虚拟机,间接把本地办法栈与虚拟机栈合二为一。
本地办法栈区域会抛出 StackOverflowError 和 OutOfMemoryError 异样。
Java 堆
Java 堆是虚拟机所治理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创立。此内存区域惟一的目标就是寄存实例对象。
Java 虚拟机标准中的形容:所有的对象实例以及数组都在堆上调配。然而,随着 JIT 编译器的倒退和逃逸剖析技术逐步成熟,栈上调配、标量替换优化技术使得所有的对象都在堆上调配也不那么“相对”了。
Java 堆是垃圾回收治理的次要区域,因而也有“GC 堆”的叫法。
依据 Java 虚拟机标准的规定,Java 堆能够处于物理上不间断的内存空间中,只有逻辑上是间断的即可。如果在堆中没有内存实现实例调配,并且堆也无奈再扩大时,将会抛出 OutOfMemoryError 异样。
办法区
办法区与 Java 堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、动态变量、即时编译器编译后的代码等数据。
办法区不须要间断的内存,能够抉择固定大小或者可扩大,还能够抉择不实现垃圾收集。办法区的内存回收的次要指标是针对常量池的回收和对类型的卸载。
当办法区无奈满足内存调配需要时,将抛出 OutOfMemoryError 异样。
运行时常量池
运行时常量池是办法区的一部分,class 文件中除了有类的版本、字段、办法、接口等形容信息外,还有一项信息是常量池,用于寄存编译期生成的各种字面量和符号援用,这部分内容将在类加载后进入办法区的运行时常量池。当常量池无奈再申请到内存时将抛出 OutOfMemoryError 异样。
间接内存
间接内存并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机标准中定义的内存区域。
在 NIO 类中,引入了一种基于通道(Channel)与缓冲区的 I / O 形式,能够应用 Native 办法间接调配堆外内存,而后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的援用进行操作。这样能在某些场景中显著进步性能,起因时防止了在 Java 堆和 Native 堆中来回复制数据。然而,当各个内存区域总和大于物理内存限度(包含物理的和操作系统零碎级的限度),也会导致动静扩大时呈现 OutOfMemoryError 异样。