news 2026/4/3 3:08:48

JVM篇1:java的内存结构 + 对象分配理解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JVM篇1:java的内存结构 + 对象分配理解

JVM 内存结构 + 对象分配详解(HotSpot 虚拟机,JDK 8 ~ 21+ 主流版本)

下面内容基于 HotSpot JVM(Oracle/OpenJDK 默认实现),2025–2026 年主流生产环境基本没有大变化(PermGen 已彻底移除,Metaspace 仍是常态)。

一、JVM 运行时数据区整体划分(线程共享 vs 线程私有)

JVM 内存主要分为以下几个逻辑区域:

区域名称是否线程共享生命周期主要存储内容可能抛出的 OOM 异常是否会 GC
程序计数器 (PC Register)私有线程生命周期当前线程执行的字节码指令地址(分支、循环、异常跳转等)几乎不会 OOM
Java 虚拟机栈 (VM Stack)私有线程生命周期栈帧(局部变量表、操作数栈、动态链接、方法出口等)StackOverflowError / OOM
本地方法栈 (Native Method Stack)私有线程生命周期native 方法(JNI 调用 C/C++)的栈帧StackOverflowError / OOM
Java 堆 (Heap)共享JVM 启动 ~ 关闭几乎所有对象实例、数组OutOfMemoryError: Java heap space是(重点 GC 区域)
元空间 (Metaspace)共享JVM 启动 ~ 关闭类元数据、方法字节码、常量池、符号引用、注解等OutOfMemoryError: Metaspace是(Full GC 时可能回收)
直接内存 (Direct Memory)NIO ByteBuffer.allocateDirect() 分配的 off-heap 内存OutOfMemoryError: Direct buffer memory否(手动或 GC 间接回收)

最核心一句话记忆

二、HotSpot JVM 堆内存详细布局(分代 + G1 时代主流视图)

现代 HotSpot(JDK 8+)默认使用分代思想,但具体收集器不同,物理布局有差异。

1. 最经典的分代布局(Parallel / CMS 时代常见)
Heap ├── Young Generation(新生代) ≈ 1/3 heap │ ├── Eden(伊甸园) ≈ 8/10 young │ └── Survivor(幸存者区)×2 From / To 各 ≈ 1/10 young └── Old Generation(老年代 / 养老区) ≈ 2/3 heap
2. G1 收集器时代(JDK 9+ 默认,2025–2026 生产主流)

G1 已经取消严格的连续 Young/Old 区域,而是把整个堆切成很多个Region(默认 2048 个,可调):

G1 内存布局示意(逻辑分代,物理碎片化):

Heap → 很多个 Region(大小相等) ┌───────────────┐ │ Eden Regions │ ├───────────────┤ │ Survivor Regs │ ├───────────────┤ │ Old Regions │ ├───────────────┤ │ Humongous Reg │ ← 大对象专用 └───────────────┘

三、Java 对象创建 & 内存分配全过程(面试高频)

new 对象时 JVM 做了什么?(8 个步骤)

  1. 类加载检查
    遇到 new 指令 → 先检查常量池中是否有该类的符号引用 → 如果没有则触发类加载(加载 → 链接 → 初始化)

  2. 分配内存(核心步骤)
    在堆中划出一块确定大小的内存给对象(对象大小在类加载后已知)。

    分配方式两种(取决于堆是否规整):

    方式适用收集器堆是否规整原理并发安全解决方案
    指针碰撞Serial / ParNew指针向空闲端移动 size 距离TLAB(线程本地分配缓冲)
    空闲列表CMS / G1(部分情况)从空闲列表中找一块足够大的空间CAS + 失败重试

    TLAB(Thread Local Allocation Buffer)是 HotSpot 解决并发分配的优化:

  3. 初始化零值
    分配的内存空间(对象头除外)全部置为零值(保证字段不赋初值也能用)

  4. 设置对象头

  5. 执行 方法(构造器)
    按照代码顺序执行父类构造 → 成员变量显式赋值 → 构造代码块 → 构造方法体

四、对象分配的“特殊规则”(面试加分项)

  1. 大对象直接进老年代
    -XX:PretenureSizeThreshold=(默认 0)
    大于这个值的对象直接分配到老年代(避免在 Survivor 来回复制)

  2. 动态年龄判定(Survivor 区晋升老年代规则)
    如果 Survivor 空间中相同年龄的所有对象大小总和 > Survivor 空间的一半(默认 50%,-XX:TargetSurvivorRatio),年龄 >= 该年龄的对象直接晋升老年代

  3. 长期存活的对象进入老年代
    默认经历 15 次 Minor GC 后晋升(-XX:MaxTenuringThreshold=15)

  4. 空间分配担保
    Minor GC 前,老年代最大可用连续空间 < 新生代所有对象总大小 → 提前 Full GC

五、快速记忆口诀(面试背诵版)

内存结构口诀
“程栈本堆元,私私私共共”
程序计数器、虚拟机栈、本地方法栈(私有)
堆、元空间(共享)

堆内布局口诀(分代时代):
“新生伊甸幸存俩,老年养老养老家”

对象分配口诀
“先查类加载 → 指针碰撞或空闲列表 → TLAB 加速 → 零值填充 → 对象头 → 构造执行”

晋升老年代三板斧
大 → 直接老
老 → 年龄阈值(默认 15)
多 → 动态年龄判定(同龄 > Survivor/2)

希望这篇能让你对 JVM 内存结构 + 对象分配有清晰的整体认知。
下一期想看哪个方向?

随时告诉我!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/28 9:52:52

从夯到拉,锐评13个 Java Web 框架!

来源&#xff1a;juejin.cn/post/7585727457472593920 &#x1f449; 欢迎加入小哈的星球&#xff0c;你将获得: 专属的项目实战&#xff08;多个项目&#xff09; / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论 新项目&#xff1a;《Spring AI 项目实战》正在…

作者头像 李华
网站建设 2026/4/2 8:50:25

unet人像卡通化参数设置:新手必看配置建议

unet人像卡通化参数设置&#xff1a;新手必看配置建议 1. 功能概述 本工具基于阿里达摩院 ModelScope 的 DCT-Net 模型&#xff0c;通过 UNET 架构实现高质量的人像卡通化转换。项目由“科哥”构建并优化&#xff0c;命名为 unet person image cartoon compound&#xff0c;旨…

作者头像 李华
网站建设 2026/4/1 21:14:41

本地Jar包无法加载?Maven三大注入方式全解析,速看!

第一章&#xff1a;本地Jar包无法加载&#xff1f;问题根源与背景解析 在Java项目开发中&#xff0c;引入本地Jar包是常见需求&#xff0c;尤其是在依赖未发布至中央仓库或涉及内部工具时。然而&#xff0c;开发者常遇到“类找不到”&#xff08;ClassNotFoundException&#x…

作者头像 李华
网站建设 2026/4/2 5:23:16

AI如何破解音频加密?AudioDecrypt技术解析

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个基于深度学习的音频解密工具&#xff0c;能够分析加密音频文件的特征模式并尝试破解。要求包含以下功能&#xff1a;1.支持常见音频格式输入(WAV,MP3等) 2.使用卷积神经网…

作者头像 李华
网站建设 2026/3/31 0:23:44

企业级Oracle账号管理实战指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个Oracle账号管理系统网页应用&#xff0c;包含以下功能&#xff1a;1) 基于RBAC的账号创建表单&#xff1b;2) 权限模板选择器&#xff1b;3) 账号有效期设置&#xff1b;4…

作者头像 李华