JVM 深入浅出 :一文看懂 JVM 内存结构

文章目录

  • 1. 概述

  • 2. 程序计数器

  • 3. Java 虚拟机栈

  • 3.1. 栈深度

  • 3.2. 栈帧

  • 3.2.1. 局部变量表

  • 3.2.2. 操作数栈

  • 3.2.3. 动态链接

  • 3.2.4. 方法正常结束

  • 3.2.5. 方法异常结束

  • 4. 堆

  • 5. 方法区

  • 5.1. 去永久代过程

  • 6. 运行时常量池

  • 7. 本地方法栈

  • 8. 参考资料

1. 概述

JVM 把内存进行了划分,不同的内存区域有不同的功能。有的内存区域是线程私有的,比如 Java 虚拟机栈、本地方法栈和程序计数器,每一条线程都有自己独立的空间。有的内存区域是线程共享的,比如方法区和堆。

所以不同内存区域的功能、作用域和生命周期是不同的。本文做一个详细的分析。

根据 JVM 虚拟机规范,内存结构如下:

JVM 深入浅出 :一文看懂 JVM 内存结构_第1张图片

JVM 虚拟机规范属于概念模型,具体的实现各个厂商的会有所差异。比如方法区的设计,hotspot 在 1.7 之前使用永久代,1.7 后使用元空间。

本文主要分析 HotSpot 虚拟机的实现。

2. 程序计数器

JVM 支持多线程,采用时间片轮转的方式实现多线程并发。一个内核每一刻只能有一个线程执行,多线程下需要线程上下文切换。为了确保切换过程中,不同的线程指令和数据不会发生混乱,需要单独开辟内存空间给每个线程,进行线程隔离。这些区域包含了程序计数器、虚拟机栈、本地方法栈。这些都是线程私有内存,生命周期和线程一致。在面试中被问到并发知识的时候,大多都会被问到“请你说一下自己对于AQS原理的理解”。下面给大家一个示例供大家参加,面试不是背题,大家一定要假如自己的思想,即使加入不了自己的思想也要保证自己能够通俗的讲出来而不是背出来。在此我向大家推荐一个架构学习交流圈。交流学习伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

如果执行的不是本地方法,程序计数器记录当前线程执行的指令地址,字节码解释器通过改变该计数器的值,来决定选取下一个要执行的指令。如果执行的是本地方法,值为空(undefined)。

程序计数器的内存空间非常小,是 JVM 规定的唯一不会发生内存溢出(Out Of Memory)的区域。

3. Java 虚拟机栈

Java 虚拟机栈由栈帧组成,Java 虚拟机栈和其他常规语言的栈类似,存储本地变量或部分计算结果,处理方法的调用和返回。虚拟机栈内容不能进行直接操作,只能用来进行栈帧的入栈和出栈。方法的调用到执行完成对应的就是栈帧的入栈和出栈过程。

Java 虚拟机栈的生命周期和线程对应,在线程创建的同时创建,和程序计数器一样都是线程私有内存区域。

JVM 深入浅出 :一文看懂 JVM 内存结构_第2张图片

Java 虚拟机规范对虚拟机栈大小有这样的描述:

  • 可以使用固定大小或者动态扩展和收缩。如果是固定大小,空间大小在栈创建的时候就会确定下来。
  • 可以配置 Java 虚拟机栈的初始大小。
  • 如果栈空间可以动态扩展或者收缩,可以配置栈的最大值和最小值。

HotSpot 虚拟机栈的配置:

  • -Xss,设置虚拟机栈大小,JDK1.5 之后默认为 1M。栈深度受到这个堆栈大小的约束。在固定物理内存下减小 Java 虚拟机栈大小可以产生更多线程,但是一个进程的线程数量有约束,不能无限增加。

Java 虚拟机栈可能会发生的异常有:

  • 如果线程请求需要的栈深度大于 JVM 限定的,会发生 StackOverflowError 异常。
  • 如果 JVM 大小可以动态扩展,在扩展的时候内存不足,或者在创建新线程时内存不够创建虚拟机栈,均会发生 OutOfMemoryError 异常。

3.1. 栈深度

方法的从调用到执行完成,对应了虚拟机栈的入栈到出栈的过程。

在编译期就可以确认局部变量表的大小和操作数栈的深度,并且写入到方法表的 code 属性中,运行期间不会发生改变。所以在编译器每个栈帧的需要大小就可以确定了。栈深度由运行期决定。在面试中被问到并发知识的时候,大多都会被问到“请你说一下自己对于AQS原理的理解”。下面给大家一个示例供大家参加,面试不是背题,大家一定要假如自己的思想,即使加入不了自己的思想也要保证自己能够通俗的讲出来而不是背出来。在此我向大家推荐一个架构学习交流圈。交流学习伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

具体的栈深度受虚拟机栈大小和栈帧大小的影响,要看使用了多少栈帧,栈帧大小多少。每个栈帧的大小不一定一样,取决于各栈帧对应方法的局部变量表和操作数栈大小等。

假设我们的虚拟机栈大小固定,栈帧数量达到最大值,也就是达到最大深度,深度大小和栈帧大小的示意图如下:

JVM 深入浅出 :一文看懂 JVM 内存结构_第3张图片

上面的示意图可以看出,在 Java 虚拟机栈大小固定的情况下,如果每个栈帧都很大,最大可用深度就会变小。

上面只是一个示意图,实际上虚拟机栈深度没这么小。默认情况下 Java 虚拟机栈有 1M,平时开发时的栈帧也不会很大。

当线程请求的栈深度大于虚拟机的所允许的栈深度会发生 Stac

你可能感兴趣的:(spring,Java,Java架构,spring,boot,spring,redis,java,架构)