JVM内存管理机制

JVM执行java程序的过程:java源代码文件(.java)会被java编译器编译为字节码文件(.class),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕后,交由JVM执行引擎执行。在这个过程当中,JVM会用一段空间来存储执行程序期间需要用到的数据和相关信息,这段空间就是运行时数据区,也就是JVM内存,JVM将它所管理的内存划分为若干个不同的数据区域,如下图所示:

JVM内存管理机制_第1张图片
如图所示,我们可以知道运行时数据区分为线程私有数据区和线程共享数据区。

1.线程私有数据区

(1)程序计数器

当前线程所执行的字节码的行号指示器。字节码解释器工作时,就是通过改变计数器的值来选取下一条需要执行的字节码指令。在JVM规范中,这是唯一不会出现OOM的区域。

(2)虚拟机栈

java方法执行的栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

a.局部变量表:存放了编译期可知的各种基本数据类型、对象引用类型和returnAddress类型,它所需的内存空间在编译期间完成分配。

b.JVM规范中,对这个区域规定的两种异常:一种是如果线程请求的栈深度大于虚拟机所允许的深度,则抛出StackOverflowError,另一种是如果虚拟机栈可动态扩展且扩展时无法申请到足够的内存,则抛出OOM。

(3)本地方法栈

Native方法执行的栈帧,在虚拟机规范中,对这个区域无强制规定,由具体的虚拟机自由实现,和虚拟机栈一样,对这个区域规定了两种异常。

2.线程共享数据区

(1)堆

存放对象实例和数组,这块区域是虚拟机管理的内存中最大的一块,是垃圾收集器管理的主要区域,被称为“GC堆”,在JVM规范中,如果在堆中没有内存完成实例分配且堆也无法再扩展时,会抛出OOM。

(2)方法区

存储已被虚拟机加载的Class类信息、final常量、static静态变量、即时编译器编译后的代码等数据,这个区域又被称为“永久代”,在JVM规范中,当方法区无法满足内存分配需求时,将抛出OOM异常。

a.运行时常量池:Class类文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放,它是方法区的一部分,会受到方法区内存的限制,在JVM规范中,当常量池无法申请到内存时,会抛出OOM。

3.内存分配示例

Book b = new Book();
b.read();

如上内存分配过程为:

(1)Book类首先被加载到虚拟机的方法区。

(2)在栈中分配引用变量b,开辟内存空间。

(3)在堆中分配内存空间,将栈中引用变量b,指向堆内存的首地址。

(4)使用引用变量b,调用方法read()。

你可能感兴趣的:(java)