CANN runtime 内存池——高效显存管理策略
2026/5/29 2:14:53
直接内存的分配与回收核心是 “Native 层分配内存 + Java 层持有引用 + Cleaner 机制回收”,全程需 JVM 与操作系统协同,具体原理如下:
ByteBuffer.allocateDirect(int capacity)(JDK 推荐)或Unsafe.allocateMemory(long size)(底层 Native 调用)触发分配。-XX:MaxDirectMemorySize限制,若超过直接抛出OutOfMemoryError: Direct buffer memory。Unsafe.allocateMemory),向操作系统申请 “堆外内存”(直接内存)。DirectByteBuffer对象,该对象仅存储 “Native 地址、内存容量、读写指针” 等元数据,不存储实际数据。DirectByteBuffer关联Cleaner对象(虚引用),绑定释放直接内存的回调逻辑(Deallocator),为后续回收做准备。DirectByteBuffer对象给应用程序,程序通过该对象的 API(如get()、put())间接操作 Native 层的直接内存。Cleaner虚引用 + JVM 垃圾回收,无需手动干预(Unsafe手动分配除外)。Cleaner持有DirectByteBuffer的虚引用和Deallocator释放器,虚引用不影响DirectByteBuffer的 GC 回收。DirectByteBuffer的所有强引用(如置为null、超出作用域),使其成为 GC 不可达对象。DirectByteBuffer为可回收对象,同时将关联的Cleaner加入引用队列(ReferenceQueue)。ReferenceHandler扫描引用队列,发现Cleaner后调用其clean()方法。clean()方法触发Deallocator的run()方法,通过Unsafe.freeMemory(Native地址)调用 Native 函数。DirectByteBuffer从 Java 堆中彻底回收。DirectByteBuffer不可达,直接内存也不会立即释放。Unsafe.allocateMemory直接分配,无Cleaner关联,必须手动调用Unsafe.freeMemory释放,否则导致内存泄漏。| 环节 | 核心操作 | 依赖组件 | 关键约束 |
|---|---|---|---|
| 分配 | 操作系统划分配外内存,Java 堆创建引用对象 | Unsafe、DirectByteBuffer | 受MaxDirectMemorySize和系统总内存限制 |
| 回收 | 触发 Native 释放函数,回收堆外内存 | Cleaner、GC、ReferenceHandler | 依赖DirectByteBuff |