前言

Java虚拟机(JVM)的自动内存管理是其核心特性之一,它极大地简化了开发者的工作,减少了内存泄漏和内存溢出的问题。本文将详细介绍JVM的自动内存管理机制的内存区域与内存溢出异常问题,包括运行时数据区域、对象的创建、对象的内存布局、对象的访问定位。

一、运行时数据区域

Java虚拟机(JVM)的运行时数据区域是内存管理的核心模块,分为以下关键部分:


1. 线程私有区域(生命周期与线程绑定)

  1. 程序计数器(PC Register)

    • 记录当前线程执行的字节码指令地址(若执行Native方法则为空)。
    • 唯一无OOM的区域(无内存溢出风险)。
  2. 虚拟机栈(Java Stack)

    • 存储栈帧(Frame),每个方法调用对应一个栈帧,包含:
      • 局部变量表(基本类型/对象引用)
      • 操作数栈(计算中间结果)
      • 动态链接(指向方法区符号引用)
      • 方法出口(返回地址)
    • 可能抛出 StackOverflowError(栈深度超限)或 OOM(扩展失败)。
  3. 本地方法栈(Native Stack)

    • Native方法(如C/C++代码)提供栈空间。
    • 异常类型同虚拟机栈。

2. 线程共享区域(生命周期与JVM进程绑定)

  1. 堆(Heap)

    • 存放对象实例与数组(占内存最大部分)。
    • 垃圾收集器主要工作区域(GC堆)。
    • 可细分为:
      • 新生代(Eden + Survivor0/1)
      • 老年代(Tenured)
    • 抛出 OOM(无法分配对象且堆无法扩展)。
  2. 方法区(Method Area)

    • 存储类元数据(类型信息、字段、方法)、常量池静态变量JIT编译代码
    • JDK 8后由元空间(Metaspace)实现(替代永久代),使用本地内存。
    • 抛出 OOM(无法满足内存分配)。
  3. 运行时常量池(Runtime Constant Pool)

    • 方法区的一部分,存储编译期字面量(字符串、数字)和符号引用(类/方法/字段名)。
    • 具备动态性(如String.intern()可在运行时添加常量)。
    • 抛出 OOM(常量池溢出)。

3. 直接内存(Direct Memory)

  • 非JVM运行时数据区,但频繁使用。
  • 通过ByteBuffer.allocateDirect()分配堆外内存(NIO通道操作时避免复制数据)。
  • 受系统内存限制,抛出 OOMOutOfMemoryError: Direct buffer memory)。

核心总结

区域存储内容异常类型线程共享性
程序计数器指令地址私有
虚拟机栈栈帧(局部变量/操作栈等)StackOverflowError / OOM私有
本地方法栈Native方法栈帧StackOverflowError / OOM私有
对象实例、数组OOM共享
方法区(元空间)类元数据、常量池、静态变量OOM共享
运行时常量池字面量、符号引用OOM共享
直接内存NIO缓冲数据OOM(堆外)共享

关键点

  • 线程私有区(PC/栈)随线程生灭,无需GC。
  • 共享区(堆/方法区)是GC主战场,需关注内存溢出。
  • 直接内存不受JVM堆限制,但影响系统内存稳定性。

二、对象的创建

在HotSpot虚拟机中,对象的创建过程可概括为以下关键步骤:

1. 类加载检查

  • 触发条件:遇到new字节码指令。
  • 检查内容
    • 常量池中是否存在该类的符号引用
    • 类是否已被加载、解析、初始化
  • 未加载时:先执行类加载过程(详见第7章)。

2. 内存分配

  • 分配方式(由堆内存是否规整决定):
    • 指针碰撞(Bump The Pointer):
      • 适用场景:堆内存规整(如Serial、ParNew等带压缩功能的收集器)。
      • 操作:移动分界指针,划出与对象大小相等的空间。
    • 空闲列表(Free List):
      • 适用场景:堆内存不规整(如CMS基于清除算法的收集器)。
      • 操作:从空闲内存块列表中找到足够大的空间分配。
  • 并发处理
    • CAS+失败重试:同步保证分配原子性。
    • TLAB(Thread Local Allocation Buffer):
      • 为每个线程预分配私有内存缓冲区,避免竞争。
      • 缓冲区用尽时,再同步申请新缓冲区。

3. 初始化零值

  • 将分配的内存空间(除对象头)初始化为零值(0、false、null等)。
  • 目的:确保字段不赋初值可直接使用(如int默认为0)。
  • TLAB优化:分配缓冲区时同步完成初始化。

4. 设置对象头

  • 存储对象关键信息:
    • Mark Word:哈希码(延迟计算)、GC分代年龄、锁状态标志等。
    • 类型指针:指向方法区的类元数据(确定对象所属类)。
    • 数组长度(若为数组对象)。
  • :锁状态等信息根据虚拟机状态动态设置(如是否启用偏向锁)。

5. 执行构造函数(<init>

  • 从虚拟机视角看,对象已生成;但从程序视角,对象尚未初始化。
  • 调用构造函数
    • 按程序员逻辑初始化字段(赋予实际值)。
    • 执行对象构造代码块(如{}或静态块)。
  • 完成标志:真正可用的对象被完全构造。

关键流程图

new指令 → 类加载检查 → 内存分配(指针碰撞/空闲列表) → 初始化零值 → 设置对象头 → 执行构造函数 → 可用对象

核心特点

  • 高频操作:对象创建极频繁,需高效处理(如TLAB避免锁竞争)。
  • 并发安全:通过CAS或TLAB解决多线程分配冲突。
  • 空间优化:零值初始化减少冗余赋值,提升效率。

这一过程平衡了性能(内存分配效率)、安全(并发控制)和规范(JVM语义一致性)。

三、对象的内存布局

在HotSpot虚拟机中,对象在堆内存中的存储布局可分为三个部分:

1. 对象头(Header)

  • Mark Word(标记字段):
    • 存储对象自身的运行时数据:哈希码(HashCode)、GC分代年龄、锁状态标志(如偏向锁、轻量级锁)、线程持有的锁、偏向线程ID、偏向时间戳等。
    • 特点:长度随虚拟机位数变化(32位系统占4字节,64位系统占8字节),为节省空间会按对象状态复用存储位(如未锁定状态下存哈希码,加锁后存锁指针)。
  • 类型指针(Class Pointer):
    • 指向方法区中对象的类型元数据(Class元信息),用于确定对象属于哪个类。
    • 例外:如果是数组对象,还需额外存储数组长度(4字节)。

2. 实例数据(Instance Data)

  • 对象实际存储的有效信息,即代码中定义的字段内容(包括父类继承的字段)。
  • 存储规则
    • 字段顺序受虚拟机分配策略参数(-XX:FieldsAllocationStyle)和源码定义顺序影响。
    • 默认策略:相同宽度的字段分配在一起(如long/doubleintshort/charbyte/boolean引用类型)。
    • 子类字段可能在父类字段的空隙中插入(通过-XX:CompactFields控制,默认开启)。

3. 对齐填充(Padding)

  • 非必需部分,仅用于占位。
  • 作用:确保对象起始地址是8字节的整数倍(HotSpot内存管理的要求),提高内存访问效率。
  • 触发条件:当对象头+实例数据总大小不是8字节倍数时,自动填充补齐。

内存布局示例

以64位系统下的普通对象为例:

|------------------------|-----------------------|
|      Mark Word (8B)    |   Class Pointer (4B)  |  → 对象头(12B)
|------------------------|-----------------------|
|       int a (4B)       |       short b (2B)    |  → 实例数据(6B)
|------------------------|-----------------------|
|     (对齐填充 2B)       |                       |  → 填充至总大小20B(8的倍数)
|------------------------|-----------------------|

说明:实际占用18B,但需填充至24B(8字节对齐),具体对齐规则由虚拟机实现决定。


关键总结

部分内容作用
对象头Mark Word + 类型指针(+数组长度)存储运行时元数据、锁信息、类元数据指针
实例数据对象字段值存储对象实际有效信息
对齐填充空白字节满足内存对齐要求,提升访问性能

这种结构设计平衡了空间效率(如字段重排减少空隙)和访问性能(如内存对齐优化CPU读取速度)。

三、对象的访问定位

在Java虚拟机中,对象访问定位是指通过栈上的引用(reference)访问堆中对象实例的方式。主要有两种实现方式:

1. 句柄访问

  • 机制:在Java堆中划分一块内存作为句柄池,引用存储的是对象的句柄地址。句柄包含两部分:
    • 指向对象实例数据的指针(堆中)
    • 指向对象类型数据的指针(方法区)
  • 优点:对象移动时(如GC整理内存),只需更新句柄中的实例数据指针,引用本身无需修改。
  • 缺点:访问对象需两次指针跳转(引用→句柄→实例数据),效率较低。

2. 直接指针访问

  • 机制:引用直接存储对象地址,对象内存布局需额外存储类型数据的指针(如对象头中的类型指针)。
  • 优点:只需一次指针跳转,访问速度更快(无句柄中间层)。
  • 缺点:对象移动时需更新所有引用(如GC需修正指针)。


HotSpot虚拟机的选择

  • 默认策略:使用直接指针访问(如Serial、Parallel Scavenge等收集器),因对象访问频繁,减少一次指针定位可显著提升性能。
  • 例外:Shenandoah收集器采用转发指针(Brooks Pointer),在对象头添加额外指针,支持并发移动对象时通过自愈(Self-Healing)机制更新引用。

 核心总结

访问方式性能对象移动稳定性实现复杂度
句柄访问较慢(两次跳转)高(引用不变)简单
直接指针(一次跳转)低(需更新引用)需额外设计

HotSpot优先选择直接指针,在速度与内存布局设计间取得平衡;而Shenandoah等收集器通过转发指针优化并发场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88420.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88420.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88420.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

位图入门算法191. 位1的个数

题目链接&#xff1a; 191. 位1的个数 - 力扣&#xff08;LeetCode&#xff09; 这道题让我们找出一个数字中二进制中1的个数&#xff0c;这个题目我们就用1的&来解决&#xff0c;最后一位有0为0&#xff0c;都是1才是1&#xff0c;我们只需要判断32次即可。 代码如下&am…

[架构之美]虚拟机Ubuntu密码重置

[架构之美]虚拟机Ubuntu密码重置 当您在虚拟机中运行Ubuntu系统时&#xff0c;忘记密码不再意味着数据丢失&#xff01;本文将详细介绍可靠的密码重置方法&#xff0c;帮助您快速恢复系统访问权限。 一、虚拟机密码重置原理与准备 1.1 为什么虚拟机重置密码更容易 在虚拟机环…

kotlin中withContext,async,launch几种异步的区别

在 Kotlin 协程中&#xff0c;withContext、async 和 launch 是常用的异步/并发操作函数&#xff0c;它们的主要区别在于用途和返回值&#xff1a;1. launch 作用&#xff1a;启动一个新的协程&#xff0c;用于执行不返回结果的并发任务。使用场景&#xff1a;适合执行没有返回…

git 报错fatal: refusing to merge unrelated histories

解决方案在你操作命令后面加--allow-unrelated-histories 例如&#xff1a; git merge master --allow-unrelated-historiesgit pull或者git push报fatal: refusing to merge unrelated histories 同理&#xff1a; git pull origin master --allow-unrelated-histories

Android 13----在framworks层映射一个物理按键

基于Android 13.一、映射步骤确定要映射的物理按键值在kl文件中增加键值对在InputEventLabels.cpp增加AKEYCODE在keycodes.h中定义AKEYCODE值attrs.xml中增加KEYCODEKeyEvent.java中增加KEYCODE在PhoneManagerWindow等相关类中进行拦截处理相关KEYCODE&#xff0c;属于具体的业…

【Java EE】Mybatis-Plus

1. 开始先进行和以前一样的项目配置、数据库连接配置&#xff0c;在这些基础上&#xff0c;额外引入 Mybatis-Plus 依赖即可。<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><vers…

各版本操作系统对.NET支持情况(250707更新)

借助虚拟机和测试机&#xff0c;检测各版本操作系统对.NET的支持情况。 安装操作系统后&#xff0c;安装相应运行时并能够运行星尘代理或幸运四叶草为通过条件。 测试平台&#xff1a;VMware Workstation 镜像来源&#xff1a;MSDN I Tell You 参考&#xff1a; .NET Fram…

5-Kafka-replication(副本机制)概念

&#x1f504; Kafka 副本机制&#xff08;Replication&#xff09; 核心概念概念说明Replica (副本)分区的完整拷贝&#xff0c;分布在不同 BrokerReplication Factor副本总数&#xff08;含 Leader&#xff09;&#xff0c;生产环境建议 ≥3Leader Replica处理所有读写请求&a…

langgraph的ReAct应用

一、什么是langgraph的ReActLangGraph 中的 ReAct&#xff08;Reasoning Acting&#xff09;代理是一种结合推理与行动能力的 AI 代理架构&#xff0c;通过动态决策链实现复杂任务处理。以下是其核心要点及实践指南。1、ReAct 代理的核心原理1.1工作流程&#xff1a;ReAct 代理…

一个编辑功能所引发的一场知识探索学习之旅(JavaScript、HTML)

文章目录一个编辑功能所引发的一场知识探索学习之旅&#xff08;JavaScript、HTML&#xff09;1. 一个编辑功能案例2. 知识点探索学习3. 参考资料一个编辑功能所引发的一场知识探索学习之旅&#xff08;JavaScript、HTML&#xff09; 1. 一个编辑功能案例 HTML&#xff1a; &l…

kali制作Windows木马

环境描述&#xff1a;攻击机&#xff1a;Kali-2025实验靶机&#xff1a;Windows11不要攻击他人&#xff0c;这只是网络安全实验还是一样获取IP地址制作好之后开服务&#xff0c;上传下载在靶机右键保留下载记得把防火墙&#xff0c;安全中心关了否则无法下载之后就可以kali控制…

从零实现一个GPT 【React + Express】--- 【1】初始化前后端项目,实现模型接入+SSE

摘要 本系列文章主要是实现一个能够对话以及具有文生图等功能的模型应用。主要UI界面会参考chat-gpt,豆包等系列应用。模型使用的是gpt开源的大模型。 如果你是一个前端开发工程师需要一个自己的开源项目&#xff0c;可以学习这个系列的文章&#xff0c;不需要有很完整的后端…

【PTA数据结构 | C语言版】在顺序表 list 的第 i 个位置上插入元素 x

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录题目代码题目 请编写程序&#xff0c;将 n 个整数存入顺序表&#xff0c;对任一给定整数 x&#xff0c;将其插入顺序表中指定的第 i 个位置。注意&#xff1a;i 代表位序&#xff0c;从 1 开始&#xff0c;不是数…

汽车智能化2.0引爆「万亿蛋糕」,谁在改写游戏规则?

进入2025年&#xff0c;长安、奇瑞、比亚迪等各大主机厂纷纷将智能化推进至全新高度&#xff0c;中国汽车智能化竞争进入了“技术市场生态”综合较量阶段。一方面&#xff0c;各大主机厂全力推进辅助驾驶的规模化普及&#xff0c;掀起了一场关于高阶辅助驾驶的“技术平权”革命…

QT 第八讲 --- 控件篇 Widget(三)界面系列

前言&#xff1a; 在上一讲《QT 第七讲 --- 控件篇 &#xff08;二&#xff09;window系列与qrc机制》中&#xff0c;我们探讨了应用程序窗口&#xff08;QMainWindow, QWidget&#xff09;的基础结构、窗口标志、状态以及Qt强大的资源管理机制&#xff08;.qrc文件&#xff0…

广州华锐互动:AR 领域的创新与服务先锋​

&#xff08;一&#xff09;定制化服务​ 广州华锐互动秉持 “以客户为中心” 理念&#xff0c;为客户提供高度定制化 AR 解决方案。项目初期&#xff0c;通过多种方式深入了解客户需求&#xff0c;挖掘痛点。基于需求分析&#xff0c;技术团队运用自主研发技术和先进算法&…

暑假算法日记第一天

目标​&#xff1a;刷完灵神专题训练算法题单 阶段目标&#x1f4cc;&#xff1a;【算法题单】滑动窗口与双指针 LeetCode题目:1456. 定长子串中元音的最大数目643. 子数组最大平均数 I1343. 大小为 K 且平均值大于等于阈值的子数组数目2090. 半径为 k 的子数组平均值2379. 得…

【软考高项】信息系统项目管理师-第1章 信息化发展(1.5 数字化转型与元宇宙、1.6 标题类知识点、1.7 十四五规划内容汇总)

文章大纲 第1章 信息化发展1.5 数字化转型与元宇宙1.5.1 数字化转型1.5.2 元宇宙1.6 标题类知识点1.7 十四五规划内容汇总1.8 10道试题第1章 信息化发展 学习建议: 此章内容大部分为新增内容,基本是全新的章节2023年5月考试2分选择,5分案例2023年下半年各批次选择题2分左右1.…

STM32F103C8T6单片机内部执行原理及启动流程详解

引言&#xff1a;为什么深入理解STM32启动流程很重要&#xff1f;STM32F103C8T6作为嵌入式开发中最常用的单片机之一&#xff0c;其内部执行原理和启动流程是理解嵌入式系统底层运行机制的核心。无论是开发Bootloader、调试HardFault异常&#xff0c;还是优化系统启动速度&…

【python 常用的数学科学/计算机视觉等工具】

当然有&#xff01;在科学计算、机器学习、图像处理等领域&#xff0c;scikit-learn、scikit-image&#xff08;skimage&#xff09;、SciPy、OpenCV 是非常重要的库&#xff0c;但它们不是唯一的。以下是一些与它们类似或互补的项目&#xff0c;按照用途分类列出&#xff1a; …