「每天一道面试题」Java虚拟机运行时数据区包括哪些?

「每天一道面试题」Java虚拟机运行时数据区包括哪些?

Java虚拟机在执行Java程序的过程中,将它所管理的内存区域划分为若干个不同的区,这些区域各自有不同的用途和生命周期,有的区域是在虚拟机启动之后才存在,有的区域是随着线程的启动和结束而创建和销毁。根据Java虚拟机规范的规定,虚拟机内存在Java程序运行时被分为程序计数器、Java虚拟机栈、本地方法栈、堆和方法区五个区域。

程序计数器

程序计数器的内存空间很小,如果当前线程正在执行的是一个Java方法,则程序计数器值记录的是当前执行的虚拟机字节码指令的地址;如果当前线程正在执行的是一个本地方法,则程序计数器值为空。Java中的多线程是通过线程轮流切换并分配时间片来实现的,而当线程恢复执行的时候,需要恢复到原来执行的位置,程序计数器中则正确记录了执行的位置,每个线程各有一个程序计数器。需要注意的是程序计数器是Java虚拟机规范中唯一一个没有规定会抛出OutOfMemoryError异常的区域。

Java虚拟机栈

每个Java方法执行的时候都会创建一个栈帧,栈帧用于存储局部变量表、操作数栈、动态链表和方法出口等信息,每个Java方法从开始调用到执行完成的过程,都对应着一个栈帧在Java虚拟机栈中入栈到出栈的过程。在Java虚拟机规范中规定,如果线程请求的深度大于虚拟机所允许的深度,将抛出*Error异常;如果虚拟机可以动态扩展,但是在扩展时申请不到足够的内存,将会抛出OutOfMemoryError异常。Java虚拟机栈的生存周期是跟随线程的,是线程私有的。

本地方法栈

Java虚拟机栈是为执行Java方法服务的,而本地方法栈是为执行本地方法服务的,它的作用与Java虚拟机栈相似,同样它也会抛出*Error异常和OutOfMemoryError异常。本地方法栈的生存周期也是跟随线程的,也是线程私有的。

堆是Java虚拟机中内存空间最大的一块,基本上所有的对象实例及数组都在这里分配内存空间,它是所有线程共享的区域。在Java虚拟机规范中,堆可以处于物理上不连续的内存空间,只要逻辑上连续就行。当堆中没有足够内存分配时,并且此时也无法再扩展,将会抛出OutOfMemoryError异常。

方法区

方法区用于存储已被虚拟机加载的类信息、常量、静态变量和即时编译后的代码等数据。从它的作用上可以看出,它也是所有线程共享的区域。当该区域无法满足内存分配需求时,也会抛出OutOfMemoryError异常。运行时常量池是方法区的一部分,它用于存储Class文件中的常量池信息,而常量池中存储了编译期间生成的各种字面量和符号引用。