跳转至

Unsafe 类使用注意事项

一、Unsafe 是什么

sun.misc.Unsafe 提供直接操作内存、线程挂起、CAS 等底层能力。JDK 内部大量使用(AtomicIntegerConcurrentHashMapLocks)。

二、获取 Unsafe

Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);

三、常用能力

1. 直接内存分配

long addr = unsafe.allocateMemory(100);
unsafe.putInt(addr, 42);
unsafe.freeMemory(addr);

不受 JVM GC 管理,要手动释放。

2. CAS

unsafe.compareAndSwapInt(o, offset, expect, update);

3. 挂起 / 唤醒线程

unsafe.park(true, 0);       // 挂起
unsafe.unpark(thread);      // 唤醒

LockSupport 底层就是这个。

4. 对象字段偏移

long offset = unsafe.objectFieldOffset(Field f);
unsafe.getIntVolatile(o, offset);

四、坑

1. 手动释放内存

忘记 freeMemory,直接内存泄漏。

2. 偏移量算错

写错偏移量,读到错误字段,JVM crash。

3. 跨版本不兼容

JDK 内部 API,不同版本可能变。Java 9 模块化后更难用。

4. 破坏类型安全

可以在任意地址写任意类型,绕过 JVM 检查。

五、替代

  • Java 9+:VarHandle 替代 Unsafe 的字段访问。
  • java.nio.ByteBuffer.allocateDirect 分配堆外内存(受 DirectMemory 限制)。
  • java.util.concurrent.atomic 包封装了常用 CAS。

生产建议

除非写 JDK 源码级组件,否则不要直接用 Unsafe。它是内部 API,坑多。