《深入理解Java虚拟机》—— JVM内存模型(运行时数据区)

JVM运行时数据区(又称JVM内存模型)

JVM运行时数据区

程序计数器 (Program Counter Register, PCR)

由于多线程是通过线程切换争夺CPU的方式执行的,故在任一时刻,CPU其实只会执行一个线程。所以为了切换线程后CPU还能回到正确的执行位置,每一个线程都应该又一个独立的PCR,互不影响。所以 PCR是线程私有的一块较小的内存空间, 可以看作是当前线程所执行的字节码的行号指示器。

若当前执行的是非Native方法,则PCR记录的是当前字节码指令的地址;若是Native方法,则PCR为空(Undefined)。

PCR所在的内存区域是运行时数据区里唯一不会发生OOM (OutOfMemoryError) 异常的区域。

虚拟机栈 (VM Stack)

每个线程拥有自己的虚拟机栈,所以虚拟机栈也是线程私有的且生命周期与线程一样。虚拟机栈是用来专门描述Java中非Native方法的内存模型。每个方法在执行时就会在当前线程的虚拟机栈中创建一个栈帧(包括局部变量表,操作数栈,动态链接,方法出口等信息)。

每一个方法从调用到执行完成,就是虚拟机栈中一个栈帧压栈到弹栈的全部过程。

若当前线程请求的栈深超过虚拟机栈允许的深度时,就抛出 StackOverflowError异常。若虚拟机栈允许动态扩展内存,但扩展时无法申请到足够的内存,则会抛出OOM异常。

本地方法栈 (Native Method Stack)

与虚拟机栈十分相似,只不过对应处理的时Java中Native方法。

方法区 (Method Area)

用于存储已被JVM加载的类 (Class) 信息,静态常量 (static final),静态变量等信息,当方法去无法满足内存分配时抛出OOM异常。

很多人将方法区与 “永久代 (Permanent Generation, permGen)” 混为一谈,实际上二者并不等价,永久代是方法区的具体实现 (方法区是《JVM规范》中定义的概念,永久代是HotSpot虚拟机(当前使用最广,JDK中自带的虚拟机)对方法区这一概念的具体实现,而其他虚拟机并没有永久代这一概念)。

方法区里包括运行时常量池,用于存放编译器生成的各种字面量(字符串常量)与符号引用(也就是说运行时常量池包含了字符串常量池与符号引用),但运行时也可以将新的常量放入池中,如用String.intern()方法。

注:在JDK 1.7之前,运行时常量池放在方法区中,HotSpot对方法区的实现是永久代;
在JDK1.7时,将运行时常量池中的字符串常量池从方法区中移到堆里(原因大概是因为字符串常量池有时太大,方法区放不下),剩下的东西还在方法区中
在JDK1.7之后,字符串常量池还在堆中,运行时常量池还在方法区中,只不过HotSpot 移除了永久代 , 使用 元空间 (Metaspace) 代替永久代,永久代退出历史舞台(原因有永久代垃圾回收效率低等)。元空间使用的是物理内存,直接受到本机内存的限制。

堆 (Heap)

堆在JVM启动时就创建了,该区域的卫一木的就是存放对象实例与数组。

堆是垃圾收集器管理的主要区域,因此堆又被称为 “GC (Garbage Collected) 堆”。按照垃圾回收的角度看堆还可以分为新生代,老年代,详情见我的其他博客。

如果堆中没有足够的内存完成对象实例的分配且也无法扩展时,抛出OOM异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值