云计算百科
云计算领域专业知识百科平台

JVM内存结构-3.5

文章目录

  • 前言
  • 一、程序计数器
  • 二、虚拟机栈
    • 1.基本概念
    • 2.栈内存溢出
  • 三、本地方法栈
  • 四、堆
    • 4.1 堆内存溢出
  • 五、方法区
    • 5.1 方法区内存溢出
    • 5.2常量池
  • 总结

前言

JVM——java程序的运行环境。在深入学习之前,先了解它内存结构。


一、程序计数器

程序计数器是 CPU 或 JVM 中用于存放下一条待执行指令地址的核心寄存器。它是线程私有的,不用考虑内存溢出。

jvm执行指令时,程序计数器会记录下条指令的计数,执行完后,解释器会读取计数器的计数,将指令翻译为机器码,传给CPU执行。

二、虚拟机栈

1.基本概念

栈-线程运行需要的内存空间。

栈帧-组成栈的单元,方法运行需要的内存空间,包括:参数,局部变量,返回地址。

活动栈帧-正在执行方法的内存空间,一个栈只有一个。

三个常见问题:

  • 垃圾回收涉及栈内存? 不会。
  • 栈内存分配越大越好吗? 不是,一些系统默认为1m,划分越大,线程运行数越少。
  • 方法内局部变量是否线程安全?
  • 共享变量,如static修饰的静态变量,需要考虑。如果方法内局部变量未逃离方法的作用范围,则为线程安全。反之逃离范围的需要考虑,比如返回值,作为参数传入。

2.栈内存溢出

栈帧过多会导致内存溢出。 在这里插入图片描述 栈帧过大也会导致内存溢出。 在这里插入图片描述 而在Java中报错:StackOverFlowError来表示栈内存溢出。

三、本地方法栈

本地方法栈是 JVM 运行时数据区的重要组成部分,专门支撑本地(Native)方法的执行。支撑native修饰的方法执行。

执行过程:

  • 入栈:为 Native 方法创建栈帧,存储方法的局部变量、参数、返回地址等;
  • 执行:通过 JNI(Java NativeInterface)调用底层操作系统 / 硬件的原生接口;
  • 出栈:方法执行完毕后,释放栈帧内存,返回结果到 Java 层。

四、堆

堆是 JVM 运行时数据区中最大、最核心的一块内存区域,也是所有线程共享的内存空间,主要用于存储 Java 程序运行时创建的对象实例和数组,是垃圾回收(GC)的核心操作区域。比如:new关键字创建的对象会使用堆内存。

4.1 堆内存溢出

堆溢出本质是,对象创建速度 > GC 回收速度,或堆空间不足以容纳存活对象。两种常见堆溢出场景:内存泄漏和内存溢出。

内存泄漏,程序创建的对象不再使用,但仍被强引用持有(如静态集合、未关闭的连接),导致 GC 无法回收,堆内存被持续占用直至耗尽。

典型场景:

  • 静态集合(static List/Map)无限添加对象,且永不清理;
  • 线程池 / 连接池未合理配置,核心线程长期持有大对象引用;
  • 监听器 / 回调函数未移除,导致对象无法被回收;
  • IO 流 / 数据库连接未关闭,底层资源对象泄漏。

内存溢出,程序本身需要创建大量存活对象(如处理超大数据集),堆配置的最大内存不足以支撑业务需求,即使 GC 回收了所有无用对象,仍无法分配新内存。

典型场景:

  • 加载超大文件 / 数据集到内存(如一次性读取 10GB 日志到 List);
  • 高并发场景下短时间创建大量临时对象,Minor GC来不及回收;
  • JVM 参数 -Xmx 配置过小,远低于业务实际需要。

在java中报错:OutOfMemoryError: java heap space。

五、方法区

方法区是是 JVM 运行时数据区中线程共享的一块内存区域,也被称为 “永久代”(JDK 8 前)或 “元空间”(JDK 8+),核心作用是存储类的元数据、常量、静态变量等与类结构相关的信息,是类加载机制的核心载体。

JAva JDK8前的方法区 在这里插入图片描述 JDK8后的方法区

5.1 方法区内存溢出

  • JDK 7 及之前:异常类型为 java.lang.OutOfMemoryError: PermGen space(永久代溢出);
  • JDK8 及之后:异常类型为 java.lang.OutOfMemoryError: Metaspace(元空间溢出);

方法区内存溢出的最常见原因:动态生成大量类

  • Spring/CGLib/ASM 动态代理:如批量为类生成代理类(每个代理类都是新的 Class 对象);
  • JSP 动态编译:JSP每次修改都会重新编译为 Servlet 类,热部署频繁时类数量暴增;
  • 动态字节码生成:如反射、动态代理框架(MyBatis、Hibernate)批量生成映射类。

5.2常量池

常量池:一张常量表,虚拟机指令根据这张表找到要执行的类名、方法名、参数类型、字面量等信息。

运行时常量池,常量池是.class文件的,当该类被加载时,其信息会加载到运行时常量池中,并将里面的符号地址变为真实地址。


总结

附上整个JVM内存结构概览。学习JVM,对学习JUC原理还是更顺畅。

赞(0)
未经允许不得转载:网硕互联帮助中心 » JVM内存结构-3.5
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!