当前位置: 首页 > news >正文

【JVM】JVM的内存结构是怎样的?

JVM的内存结构是Java程序运行时内存管理的核心,不同区域有明确的职责。

一、整体划分

包括两大部分,分为线程私有区域(随线程创建/销毁,无需垃圾回收)和线程共享区域(所有线程共用,需要垃圾回收管理)。

  • 线程私有区域:程序计数器、虚拟机栈、本地方法栈。 支撑线程独立执行(如方法调用、指令跟踪)
  • 线程共享区域:堆、方法区(元空间)。 存储对象实例、类信息等全局数据,是内存管理的核心区域

二、各区域详解:

1.程序计数器(Program Counter Register):

  • 线程私有: 每个线程都有独立的程序计数器,互不干扰。
  • 作用:记录当当前线程 “下一条要执行的 JVM 字节码指令的地址”,为线程提供执行路标,确保线程在切换(如CPU调度被中断)后能够恢复到正确的执行位置。

若执行的是 Java 方法,计数器存储下一条要执行的字节码指令的地址;
若执行的是 Native 方法(本地方法,如 C/C++ 实现),计数器值为undefined。 因为Native方法的执行由操作系统控制,而非JVM,无需JVM记录指令地址。

特点:
1.内存空间极小,几乎不占用资源。
2.是JVM中唯一不会发生OutOfMemoryError(OOM) 的区域
3.本质是线程执行的路标,确保线程切换(如CPU调度)后能恢复到正确执行的位置。

2.虚拟机栈:

  • 线程私有:每个线程创建时,会分配一个虚拟机栈生命周期与线程一致。
  • 作用:记录方法调用的执行状态,每个方法调用时,会创建一个栈帧,栈帧入栈;方法执行完毕,栈帧出栈。
  • 栈帧包含的内容:
    1.局部变量表: 存储方法内的局部变量(如基本类型、对象引用),容量在编译期确定;
    2.操作数栈:方法执行时的临时数据存储区(如计算a+b时,先将a和b入栈,再执行加法);
    3.动态链接:指向方法区中该方法的符号引用(运行时转换为直接引用)
    4.返回地址:方法执行完后,回到调用者的位置(如main方法调用func(),func()执行完需回到main的下一行)。

可能的异常:
1.StackOverflowError:线程请求的栈深度超过虚拟机允许的最大深度(如递归调用无终止条件);
2.OutOfMemoryError:虚拟机栈可动态扩展时,扩展失败(如创建过多线程,栈内存总需求超过系统内存)。

3.本地方法栈:

  • 线程私有:与虚拟机栈功能类似,但专门为 Native 方法(非 Java 实现的方法)服务。
  • 特点:
    可能抛出StackOverflowError(栈深度超限)和OutOfMemoryError(内存不足),与虚拟机栈一致。

4.堆:

  • 线程共享:JVM中内存占比最大的区域,几乎所有对象实例(包括数组)都在这里分配内存。
  • 作用存储对象实例,是**垃圾回收(GC)**的主要工作区域。
  • 结构划分:
    堆空间通常按照对象“存活时间”划分为以下区域:
    • 新生代:存放新创建的对象,分为:
      • Eden区(伊甸园):新对象优先分配到这里。
      • Survivor 区(幸存者区):分为 From 和 To 两个大小相等的区域,用于存放 Eden 区回收后存活的对象(每次 GC 后,存活对象在 From 和 To 之间转移,经过多次存活后进入老年代)。
    • 老年代:存放存活时间长的对象(如经过多次年轻代 GC 仍存活的对象)。

特点:
1.堆的大小可通过**-Xms(初始堆大小)和-Xmx(最大堆大小)参数配置(尽可能两者设为一致,避免动态扩展消耗性能);
2.是
OOM 最常见的区域**(如创建对象过多且无法被 GC 回收,堆空间耗尽时抛出java.lang.OutOfMemoryError: Java heap space)。

5.方法区:

  • 线程共享:存储已被 JVM 加载的类信息、常量、静态变量、即时编译器(JIT)编译后的代码等数据。
  • 历史演进
    • JDK 7 及之前:方法区的实现称为 “永久代(PermGen)”,属于堆的一部分,大小固定(易 OOM);
    • JDK 8 及之后:永久代被元空间(Metaspace) 取代,元空间不再使用堆内存,而是直接使用本地内存(Native Memory),大小受系统内存限制(更灵活)。
  • 运行时常量池
    是方法区的一部分,存放编译期生成的符号引用和字面量(如字符串常量"abc")。

三、各区域的协作关系:

Java 程序运行时,内存流转大致如下:
1.类加载器将类信息加载到方法区(元空间)
2.主线程启动,创建虚拟机栈,main方法的栈帧入栈;
3.执行new Object()时,在中创建对象实例,栈帧的局部变量表存储该对象的引用(地址);
4.程序计数器记录当前执行的字节码指令地址,确保线程切换后能继续执行;
5.方法执行完毕,栈帧出栈;对象不再被引用时,由 GC 在堆中回收。

http://www.dtcms.com/a/346658.html

相关文章:

  • 调味品生产过程优化中Ethernet/IP转ProfiNet协议下施耐德 PLC 与欧姆龙 PLC 的关键通信协同案例
  • 字符串的大小写字母转换
  • linux中文本文件操作之grep命令
  • Linux-常用文件IO函数
  • Java:类及方法常见规约
  • UE5多人MOBA+GAS 53、测试专属服务器打包和连接,以及配置EOS
  • linux编程----网络通信(TCP)
  • 利用Prometheus监控服务器相关数据
  • SpringBoot自动配置原理解析
  • 本地文件夹即时变身 Web 服务器(文件服务器)
  • Linux问答题:归档和传输文件
  • Reactor 反应堆模式
  • 《解构React Server Components:服务端序列化与流式传输的底层逻辑》
  • 为什么在WHERE子句里使用函数,会让索引失效
  • 中农具身导航赋能智慧农业!AgriVLN:农业机器人的视觉语言导航
  • 【数据结构】计数排序:有时比快排还快的整数排序法
  • Linux PCI 子系统:工作原理与实现机制深度分析
  • 并查集详解
  • 第三阶段数据库-9:循环,编号,游标,分页
  • 【数据分析】宏基因组荟萃分析(Meta-analysis)的应用与实操指南
  • ES作为推荐库的设计原理
  • 配置npm国内源(包含主流npm镜像源地址)
  • Docker之nginx安装
  • 青少年机器人技术(五级)等级考试试卷(2020年9月)
  • docker的数据管理
  • 工作空间与功能包
  • 解读66页数字化转型数据中台规划应用实践解决方案【附全文阅读】
  • Q/DR/CX7.2-2020 是中国企业标准体系中
  • 【2025CVPR-目标检测方向】UniMamba:基于激光雷达的3D目标检测,采用分组高效曼巴语进行统一空间信道表示学习
  • Qt + windows+exe+msvc打包教程