news 2026/7/7 19:21:34

直接内存的释放原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
直接内存的释放原理

直接内存的释放核心依赖 Cleaner 机制(虚引用) ,配合 JVM 垃圾回收触发,无需手动调用 Native 方法,具体原理如下:
一、释放的核心依赖:Cleaner 与虚引用
1. Cleaner 的本质:sun.misc.Cleaner是 Java 中的虚引用实现,继承自PhantomReference,专门用于跟踪对象生命周期并触发资源释放。
2. 关联逻辑:创建DirectByteBuffer时,JVM 会同时创建一个Cleaner对象,将其与DirectByteBuffer绑定。
◦ Cleaner会持有两个关键引用:一是指向DirectByteBuffer的虚引用,二是指向释放直接内存的回调函数(Deallocator)。
◦ DirectByteBuffer本身存储在 Java 堆中,仅作为直接内存的 “引用句柄”,不存储实际数据。
二、释放的完整流程
1. 触发条件:当DirectByteBuffer对象失去所有强引用(如引用被置为null),且 JVM 执行 GC 时,该对象会被标记为可回收。
2. 虚引用触发:GC 发现DirectByteBuffer可回收后,会将关联的Cleaner对象加入到 “引用队列”(ReferenceQueue)。
3. 执行释放回调:JVM 内部有一个后台线程(ReferenceHandler),会持续扫描引用队列。
◦ 当检测到队列中的Cleaner时,会调用其clean()方法。
◦ clean()方法会触发Deallocator的run()方法,通过 Native 调用(如Unsafe.freeMemory())释放对应的直接内存。
4. 最终回收:DirectByteBuffer对象被 GC 从堆中回收,直接内存被操作系统回收,完成整个释放流程。
三、关键细节说明
1. 无需手动调用释放方法:只要DirectByteBuffer的强引用被释放,GC 触发后会自动通过Cleaner完成直接内存释放,无需手动调用freeMemory()。
2. 释放的不确定性:释放时机依赖 GC 触发时机,若DirectByteBuffer长期被强引用(如静态变量持有),GC 不会回收该对象,Cleaner也不会触发,会导致直接内存泄漏。
3. 显式辅助释放:对于大容量直接内存,可主动置空DirectByteBuffer引用(buffer = null),配合System.gc()(仅建议,不依赖)提示 JVM 触发 GC,加速释放,但System.gc()可能被-XX:+DisableExplicitGC参数禁用。
4. 特殊情况:直接使用 Unsafe 分配:若通过Unsafe.allocateMemory()手动分配直接内存,不会关联Cleaner,必须手动调用Unsafe.freeMemory()释放,否则会造成永久内存泄漏。
四、常见误区澄清
• 误区 1:DirectByteBuffer被 GC 回收 = 直接内存释放?
不成立。DirectByteBuffer的回收是前提,真正释放直接内存的是Cleaner的回调,两者是 “触发与执行” 的关系。
• 误区 2:手动调用buffer.clear()能释放直接内存?
不能。clear()仅重置缓冲区的读写指针,不会释放DirectByteBuffer的强引用,也不会触发直接内存释放。

直接内存的释放流程是怎样的?

直接内存的释放流程核心是 “强引用失效→GC 标记→Cleaner 回调→Native 释放”,全程由 JVM 协同 Cleaner 机制自动完成,具体步骤如下:
1. 前提:DirectByteBuffer 失去强引用
• 应用程序中持有DirectByteBuffer的强引用被销毁(如引用变量置为null、超出作用域)。
• 此时DirectByteBuffer对象成为 GC 可达性分析中的 “不可达对象”,仅保留与Cleaner的虚引用关联。
2. GC 触发并标记可回收对象
• JVM 执行垃圾回收(Minor GC 或 Full GC),扫描到DirectByteBuffer已不可达。
• GC 不会直接回收DirectByteBuffer,而是先检测到其关联的Cleaner(虚引用),并将Cleaner对象加入预设的 “引用队列”(ReferenceQueue)。
3. 后台线程处理引用队列
• JVM 启动时会创建一个优先级最高的后台线程ReferenceHandler,专门循环扫描引用队列。
• 当线程发现队列中新增Cleaner对象时,会调用其clean()方法,触发释放逻辑。
4. 执行 Native 方法释放直接内存
• Cleaner的clean()方法会调用内部关联的Deallocator(释放器)的run()方法。
• Deallocator通过Unsafe.freeMemory()(Native 调用),直接向操作系统申请释放对应的堆外内存(直接内存)。
5. 最终回收堆中 DirectByteBuffer 对象
• 直接内存释放完成后,DirectByteBuffer对象不再有任何引用关联,GC 会在本次或下次回收中,将其从 Java 堆中彻底回收。
• 整个流程结束,直接内存和堆内存均完成释放。
关键补充
• 释放时机依赖 GC:若 GC 未触发,即使DirectByteBuffer不可达,直接内存也不会立即释放,可能出现 “堆内存空闲但直接内存占用高” 的情况。
• 手动辅助释放:可通过buffer = null+System.gc()(仅提示 GC,不保证立即执行)加速流程,但需注意System.gc()可能被-XX:+DisableExplicitGC禁用。
• 手动分配场景:若通过Unsafe.allocateMemory()分配直接内存,无Cleaner关联,需手动调用Unsafe.freeMemory(),否则会造成内存泄漏。

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

禁用显示回收对直接内存的影响

禁用显式回收(通过 JVM 参数-XX:DisableExplicitGC)对直接内存的核心影响是:延缓直接内存回收时机,增加内存溢出和泄漏风险,尤其在依赖System.gc()辅助释放的场景中影响显著。1. 核心影响:回收时机更难触发…

作者头像 李华
网站建设 2026/7/7 16:44:48

游戏性能优化终极指南:突破帧率限制的完整解决方案

游戏性能优化终极指南:突破帧率限制的完整解决方案 【免费下载链接】genshin-fps-unlock unlocks the 60 fps cap 项目地址: https://gitcode.com/gh_mirrors/ge/genshin-fps-unlock 还在为游戏卡顿而烦恼吗?想要体验更流畅的游戏画面&#xff1f…

作者头像 李华
网站建设 2026/7/7 14:45:08

PCL2启动器终极指南:如何快速打造完美的Minecraft游戏环境

还在为Minecraft启动器配置复杂、模组冲突频发而烦恼?PCL2社区增强版为你提供一站式解决方案,让游戏体验从此简单高效。这款强大的启动器不仅解决了传统启动器的各种痛点,更为玩家带来了前所未有的便捷操作体验。 【免费下载链接】PCL2-CE PC…

作者头像 李华
网站建设 2026/7/7 2:11:31

小米运动自动刷步数工具:3分钟配置实现微信支付宝完美同步

小米运动自动刷步数工具:3分钟配置实现微信支付宝完美同步 【免费下载链接】mimotion 小米运动刷步数(微信支付宝)支持邮箱登录 项目地址: https://gitcode.com/gh_mirrors/mimo/mimotion 还在为每天运动步数不达标而烦恼?…

作者头像 李华
网站建设 2026/7/6 17:55:39

深入理解Java类:面向对象编程的核心基石

在Java编程语言中,类(Class) 是面向对象编程(OOP)的核心与基础,它是对现实世界中事物的抽象描述,封装了事物的属性和行为,是创建对象的模板。Java类的构成主要包含两大核心元素&…

作者头像 李华
网站建设 2026/7/7 16:27:48

Windows Cleaner:免费快速解决C盘爆满的终极系统优化工具

还在为C盘爆满、系统卡顿而烦恼吗?Windows Cleaner作为一款专业的磁盘清理工具,能够智能识别并安全删除各类垃圾文件,让您的Windows系统重获流畅体验。只需简单几步,就能释放宝贵磁盘空间,告别系统运行缓慢的困扰&…

作者头像 李华