JVM如何管理直接内存?

⚙️ 一、直接内存的分配

  1. 通过Unsafe类分配
    • 直接内存的分配由java.nio.ByteBuffer.allocateDirect()触发,内部调用Unsafe.allocateMemory(size)向操作系统申请堆外内存,返回内存地址。
    • 分配时通过Bits.reserveMemory()检查是否超出-XX:MaxDirectMemorySize限制(默认与堆最大值-Xmx相同),若超出则抛出OutOfMemoryError
  2. 创建DirectByteBuffer对象
    • 堆外内存地址被封装到堆内的DirectByteBuffer对象中,同时注册Cleaner(虚引用)用于后续回收。

🔄 二、直接内存的回收机制

  1. 自动回收流程
    • 步骤1:当DirectByteBuffer对象不再被引用时,JVM垃圾回收器(GC)通过可达性分析判定其不可达,触发对象回收。
    • 步骤2:对象回收时,关联的Cleaner(虚引用)被加入引用队列(Reference Queue)。
    • 步骤3:后台线程ReferenceHandler(最高优先级守护线程)持续轮询引用队列,调用Cleaner.clean()方法。
    • 步骤4:Cleaner触发Deallocator.run(),调用Unsafe.freeMemory(address)释放堆外内存。
  2. 手动回收建议
    • 若需立即释放,可显式调用((DirectBuffer) buffer).cleaner().clean()
    • 调用System.gc()可能触发Full GC,但不推荐(可能导致STW延迟),尤其在禁用-XX:+DisableExplicitGC时无效。

⚠️ 三、关键风险与管理策略

  1. 内存泄漏风险
    • 原因:若DirectByteBuffer对象未被及时回收(如长期存活或循环引用),或禁用System.gc(),可能导致Cleaner无法触发,直接内存无法释放。
    • 排查工具:
      • jcmd VM.native_memory:查看堆外内存使用概况。
      • Arthas memory命令:监控直接内存池状态。
  2. 参数调优
    • 设置上限:-XX:MaxDirectMemorySize=512m避免超出物理内存。
    • 避免禁用显式GC:除非高并发场景需减少Full GC,否则保留-XX:-DisableExplicitGC以支持自动回收。
  3. 替代方案
    • 内存池复用:使用ByteBuffer池(如Netty的ByteBuf)减少频繁分配开销。
    • 软引用缓存:对非关键直接内存使用SoftReference,内存不足时自动回收。

💎 四、总结:直接内存管理核心流程

plaintext 复制代码
分配:Unsafe.allocateMemory() → 创建DirectByteBuffer + 注册Cleaner(虚引用)
回收:GC回收对象 → Cleaner入队 → ReferenceHandler触发Cleaner.clean() → Unsafe.freeMemory()
  • 关键依赖:虚引用 + ReferenceHandler线程 + Unsafe原生操作。
  • 最佳实践:
    • 高频I/O场景使用直接内存,但需监控MaxDirectMemorySize
    • 避免长期持有DirectByteBuffer引用,防止内存泄漏。
相关推荐
zfj3214 分钟前
CyclicBarrier、CountDownLatch、Semaphore 各自的作用和用法区别
java·开发语言·countdownlatch·semaphore·cyclicbarrier
koo3645 分钟前
pytorch深度学习笔记13
pytorch·笔记·深度学习
2501_9167665410 分钟前
【JVM】类的加载机制
java·jvm
Sag_ever10 分钟前
Java数组详解
java
张np11 分钟前
java基础-ConcurrentHashMap
java·开发语言
崎岖Qiu28 分钟前
【OS笔记36】:文件存储空间管理(一)- 空闲区表法
笔记·操作系统·存储管理·文件系统·os
一嘴一个橘子34 分钟前
spring-aop 的 基础使用 - 4 - 环绕通知 @Around
java
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
小毅&Nora1 小时前
【Java线程安全实战】⑨ CompletableFuture的高级用法:从基础到高阶,结合虚拟线程
java·线程安全·虚拟线程
码农小韩1 小时前
基于Linux的C++学习——动态数组容器vector
linux·c语言·开发语言·数据结构·c++·单片机·学习