首页 理论教育 Java程序设计:JVM内存划分知识点总结

Java程序设计:JVM内存划分知识点总结

时间:2023-11-01 理论教育 版权反馈
【摘要】:JVM在执行Java程序时会把它管理的内存区域划分为若干个不同的数据区域,统称为运行时数据区。根据《Java虚拟机规范》,JVM会把它管理的内存划分为5个不同的区域:程序计数器、虚拟机栈、本地方法栈、方法区、堆。图2-16虚拟机栈与栈帧单个线程中,对每一个调用方法,JVM都会为其分配一个栈帧。

Java程序设计:JVM内存划分知识点总结

JVM在执行Java程序时会把它管理的内存区域划分为若干个不同的数据区域,统称为运行时数据区。根据《Java虚拟机规范》,JVM会把它管理的内存划分为5个不同的区域:程序计数器(program counter register)、虚拟机栈(VM stack)、本地方法栈(native method stack)、方法区(method area)、堆(heap)。理解JVM内存划分,有助于理解Java程序的执行过程。

1.程序计数器

程序计数器的功能类似于计算机组成原理中的PC寄存器,用于存放下一条指令所在单元地址。JVM中的PC存放的是程序正在执行的字节码的行号,字节码解释器的工作就是通过改变程序计数器的值来选择下一条需要执行的字节码指令。

2.虚拟机栈

虚拟机栈,也就是我们常说的FILO栈,描述的是Java方法执行的内存模型:虚拟机栈存放每个方法执行时创建的栈帧(stack frame),每个栈帧对应一个被调用的方法。每个线程都会有一个自己的虚拟机栈,互不干扰。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建好的栈帧压栈,当方法执行完毕后,便会将该栈帧弹出栈。活动线程中,只有栈顶的栈帧是有效的,称为当前栈帧,这个栈帧所关联的方法称为当前方法,执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作。大致结构如图2-16所示。

图2-16 虚拟机栈与栈帧

单个线程中,对每一个调用方法,JVM都会为其分配一个栈帧。图2-16中,main()方法中包含一个栈帧,然后在main()方法里面调用了Computer()方法,然后这个Computer()方法也会含有自己的栈帧。

可见,栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。它是虚拟机运行时虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态链接和方法返回地址(方法出口)等信息。下面分别介绍。

1)局部变量

局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。

在方法执行时,虚拟机是使用局部变量表完成参数变量列表的传递过程,如果是实例方法,那么局部变量表中的第一个位置默认是用于传递方法所属对象实例的引用,在方法中可以通过关键字“this”来访问这个隐含的参数,其余参数则按照参数列表的顺序来排列,参数表分配完毕后,再根据方法体内部定义的变量顺序和作用域来分配剩余容量。

局部变量不像类的实例变量那样会有默认初始化值,所以局部变量需要显式初始化,如果定义了一个局部变量但没有初始化是无法使用的。

另外注意,类的静态成员(静态变量和静态方法)都存储在方法区中的静态区(这里指类被加载后,静态成员的存储位置)。

2)操作数栈(www.xing528.com)

所谓操作数是指那些被指令操作的数据,程序中的计算是通过操作数栈来完成的。

3)动态链接

每一个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用。包含这个引用的目的就是支持当前方法的代码能够实现动态链接。

4)方法返回地址

在方法退出之前,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。一般来说,方法正常退出时,调用者PC计数器的值就可以作为返回地址,栈帧中很可能会保存这个计数器值。而方法异常退出时,返回地址是要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。

方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用栈帧的操作数栈中,调用PC计数器的值以指向方法调用指令后面的一条指令等。

3.本地方法栈

该区域与虚拟机栈所发挥的作用非常相似,只是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为使用到的本地操作系统(Native)方法服务。在JVM规范中,并没有对本地方法栈的具体实现方法以及数据结构做强制规定,虚拟机可以自由实现它。

4.方法区

方法区是被各个线程共享的内存区域,用于存储已被虚拟机加载的每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。

在方法区中有一个非常重要的部分,就是运行时常量池。常量池是指在编译期被确定,并被保存在已编译的class文件中的一些数据,包括编译期生成的各种字面量、符号引用、文字字符串、final变量值、类名和方法名常量等。

5.堆

堆也是被所有线程共享的,在JVM中只有一个堆。Java中堆是用来存储对象本身以及数组的。堆也是Java垃圾收集器管理的主要区域,所以很多时候会称它为GC堆。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈