JVM运行时数据区

一、概述

Java虚拟机在执行程序的过程会把它管理的内存划分为若干个不同的数据区。这些数据区有些是随着虚拟机进程的启动而一直存在的,有些区域则是依赖线程的启动和结束而创建和销毁的。

二、程序计数器

程序计数器可以看做是当前线程所执行的字节码的行号指示器,在Java虚拟机的概念模型中,字节码解释器工作时就是通过改变这个计数器的值来读取下一条需要执行的字节码指令。如果当前线程正在执行的是一个Java方法,这个计数器记录的值就是正在执行的字节码指令地址,如果是在执行本地方法,这个计数器的值为空(Undefined)。值得注意的是,这块区域是唯一一个在《Java虚拟机规范》中没有规定任何OutOfMemoryError情况的区域。

三、Java虚拟机栈

Java虚拟机栈就是我们常说的堆栈,这块区域也是线程私有的。虚拟机栈描述的是Java方法执行的线程内存模型:当一个方法被执行时,虚拟机栈会创建一个栈帧,这个栈帧储存了局部变量表、操作数栈、动态链接、方法返回地址等信息,当方法执行完成时,栈帧出栈。

局部变量表储存了编译时期可以确定的各种基本数据类型( boolean, byte, char, short, int, float)、对象引用(reference)和returnAddress类型(指向下一条字节码指令的地址)。这些数据类型在局部变量表中以局部变量槽(Slot)来表示,long和double类型会占用两个Slot。局部变量表所需要的空间是在编译时就确定的,当调用一个方法时,这个方法需要多大的局部变量表空间是完全确定的。

在《Java虚拟机规范》中规定了这个区域的两种异常情况:

  • If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
  • If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.

如果线程请求的虚拟机栈深度超过虚拟机所允许的深度,将抛出StackOverflowError异常。如果虚拟机栈容量动态扩展时申请不到足够的内存将抛出OutOfMemoryError异常。

注:Hotspot虚拟机的栈容量不可以动态扩展,不会因为动态扩展内存不足OOM,但线程申请栈空间时,如果内存不足,还是会OOM。

四、本地方法栈

本地方法栈的作用与虚拟机栈类似,只不过虚拟机栈是为Java方法服务的,而本地方法栈是为本地方法服务的。在Hotspot中,将本地方法栈和虚拟机栈合二为一。与虚拟机一样,本地方法栈同样会在线程请求的虚拟机栈深度超过虚拟机所允许的深度和栈扩展内存不足时,分别抛出StackOverflowError和OutOfMemoryError异常

五、堆

对于大多数Java程序,Java堆是虚拟机所管理的最大的一块内存空间,Java堆是所有线程共享的一块区域,在虚拟机启动时创建,所有的类实例和数组都储存在这块区域,这个区域也是垃圾收集器主要收集的区域

《Java虚拟机规范》中规定,Java堆可以被实现为固定大小,也可以是可扩展的,目前主流的虚拟机都可以通过参数-Xmx和-Xms来设置堆的最大和最小大小。Java堆可以是物理上不连续的内存空间,但逻辑上应该是连续的。当Java堆没有足够的内存分配对象空间,并且无法再扩展时,会抛出OutOfMemoryError异常。

六、方法区

方法区和堆一样,都是所有线程共享的内存区域,用来储存类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。虽然方法区在逻辑上是堆的一部分,但简单实现可以不实现垃圾收集。和Java堆一样,方法区不需要连续的物理内存,也可以被实现为固定大小和可扩展的。这块区域的垃圾回收主要是针对常量池的回收和堆类型的卸载,一般来说回收效果都不会太好,但这块区域的回收有时候是必要的。根据《Java虚拟机规范》的规定,当方法区没有足够的内存满足新的内存分配需求时,将抛出OutOfMemoryError异常。

七、运行时常量池

运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表,用于存放编译期生成的各种字面量和符号引用,这部分内容在类加载后存放到运行时常量池。因为常量并不一定只在编译时产生的,运行时同样也能产生新的常量,所以运行时常量池允许在运行时动态地将常量放入常量池,如String::intern。由于运行时常量池是方法区的一部分,当常量池没有足够的内存满足内存分配需求时,同样会抛出OutOfMemoryError异常。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值