JVM中的运行时数据区

java虚拟机在执行java程序的过程中会把它所管理的内存划分成不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则依赖用户线程的启动和结束而建立和销毁。根据《Java虚拟机规范(Java SE7版)》的规定,Java虚拟机所管理的内存会包括以下几个运行时数据区:

程序计数器:程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。程序计数器是”线程私有“的,每个线程都有各自的程序计数器,它们之间互不影响,独立存储。如果线程执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是本地方法,这个计数器值则为空。

Java虚拟机栈:Java虚拟机栈也是线程私有的,它的生命周期与线程相同。每个方法执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接(或指指向运行时常量池的引用)、方法返回地址、一些其他的附加信息。每一个方法的调用直至执行完成的过程,就对应着一个栈帧的入栈和出栈的过程。

局部变量表存放了编译期间可知的各种基本数据类型、对象引用和returnAdress类型。局部变量表中使用变量槽(Slot)来存储变量,64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。如果虚拟机栈可以动态扩展,并且在拓展时无法申请到足够的内存,将抛出OutOfMemoryError异常。

栈帧的内部结构示意图如下:

本地方法栈:本地方法栈与虚拟机栈的作用非常相似,它们之间的区别是虚拟机栈执行Java方法服务,而本地方法栈使用到Native方法服务。和虚拟机栈一样,本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。在HotSpot虚拟机中,虚拟机栈和本地方法栈是合在一起的。

Java堆:对大多数应用来说,Java堆(Java Heap)是Java虚拟机中所管理的内存最大的一块。Java堆是被所有线程共享的一块的区域,此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

Java堆也是垃圾收集器管理的主要区域。主要分为新生代和老年代,新生代又分为Eden区,From Survivor区,To Survivor区。从内存分配的角度来看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区(TLAB)。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

方法区:方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息,常量、静态变量、运行时常量池、即时编译器编译后的代码数据等。

运行时常量池:运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池。不过,一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。运行时常量池相对于Class文件常量池的另一个重要特征是具备动态性,运行期间也可能将新的常量放入池中。当常量池无法再申请到内存时会抛出OutOfMemoryError异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值