news 2026/3/12 0:59:58

直接内存的释放原理

作者头像

张小明

前端开发工程师

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/3/11 3:56:24

Screen to Gif 延时摄影模式快速理解与应用

屏幕上的时间魔术:用 Screen to Gif 的延时摄影模式高效创作动态内容 你有没有试过录一段代码编写过程,结果生成的视频长达3分钟、几十MB,最后还得花半小时剪辑去冗?或者想在文档里插入一个操作演示,却发现平台根本不…

作者头像 李华
网站建设 2026/3/9 15:18:36

深蓝词库转换:轻松实现多平台输入法词库同步的完整指南

深蓝词库转换:轻松实现多平台输入法词库同步的完整指南 【免费下载链接】imewlconverter ”深蓝词库转换“ 一款开源免费的输入法词库转换程序 项目地址: https://gitcode.com/gh_mirrors/im/imewlconverter 在日常使用不同设备和输入法的过程中,…

作者头像 李华
网站建设 2026/3/10 7:52:39

BBDown视频下载终极指南:高效保存B站内容的完整攻略

BBDown视频下载终极指南:高效保存B站内容的完整攻略 【免费下载链接】BBDown Bilibili Downloader. 一款命令行式哔哩哔哩下载器. 项目地址: https://gitcode.com/gh_mirrors/bb/BBDown 还在为B站视频无法离线观看而烦恼吗?想要一键保存心仪UP主的…

作者头像 李华
网站建设 2026/3/11 22:19:53

MTKClient实战:解锁Nokia设备BROM模式的技术经验分享

MTKClient实战:解锁Nokia设备BROM模式的技术经验分享 【免费下载链接】mtkclient MTK reverse engineering and flash tool 项目地址: https://gitcode.com/gh_mirrors/mt/mtkclient MTKClient作为一款功能强大的联发科芯片设备处理工具,在Androi…

作者头像 李华
网站建设 2026/3/11 17:50:21

WindowsCleaner:彻底解决C盘爆红的终极清理方案

WindowsCleaner:彻底解决C盘爆红的终极清理方案 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服! 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 当电脑C盘亮起红色警告,系统运行变得卡顿不…

作者头像 李华
网站建设 2026/3/8 22:49:41

微信小程序逆向工程利器:wxappUnpacker深度解析与应用指南

微信小程序逆向工程利器:wxappUnpacker深度解析与应用指南 【免费下载链接】wxappUnpacker 项目地址: https://gitcode.com/gh_mirrors/wxappu/wxappUnpacker 在微信小程序开发学习和技术研究中,你是否曾渴望深入理解编译后小程序的内部结构&…

作者头像 李华