不能在生产环境使用 Unsafe——它是 JVM 内部工具,JDK 持续封禁;getUnsafe() 抛 SecurityException 因校验非 bootstrap 类加载器;JDK 9+ 反射失效,17+ 多方法弃用;仅能通过 --add-opens 暴力读 theUnsafe 字段;地址计算须基于对象头偏移与基址叠加,数组需用 arrayBaseOffset + arrayIndexScale;模块限制下必须显式开放权限;跨 JDK 版本行为不可靠,业务中使用风险极高。

不能在生产环境用 Unsafe 绕过安全检查——它不是黑科技,是 JVM 内部维护工具,连 JDK 自己都在逐步封禁。
为什么 Unsafe 的静态 getUnsafe() 总抛 SecurityException
因为 JVM 默认禁止应用层代码获取 Unsafe 实例:它没被设计成公开 API,getUnsafe() 会校验调用类的 class loader 是否为 bootstrap loader。你写的类几乎全是 application loader,直接被拒。
- 别试图用反射调用
getUnsafe()—— JDK 9+ 在Unsafe类里加了额外校验,反射也过不去 - JDK 17 起,
Unsafe的很多方法(如allocateMemory)已被标记为@Deprecated(forRemoval = true) - 真正能拿到实例的路子只剩一个:
java.lang.reflect.Field暴力读取Unsafe.theUnsafe字段,且需配合--add-opens启动参数放开模块限制
Unsafe 直接写内存时,putInt/putLong 等方法的地址怎么算
所有偏移量操作都基于对象头起始地址(objectFieldOffset 返回的值),不是从 0 开始的“内存绝对地址”。你得先用 staticFieldOffset 或 objectFieldOffset 拿到字段在对象内的字节偏移,再叠加对象基址(allocateInstance 或 getObject 得到的引用)。
- 对象基址 ≠
System.identityHashCode()—— 后者只是哈希码,和内存布局无关 - 用
unsafe.addressSize()判断当前平台是 4 字节还是 8 字节寻址,影响指针计算 - 对数组操作要用
arrayBaseOffset(Class)+arrayIndexScale(Class)才能得到第 n 个元素的真实地址,别直接乘 4 或 8
JDK 9+ 模块系统下,连 Unsafe 字段都读不到怎么办
模块封装后,默认禁止外部读取 sun.misc.Unsafe.theUnsafe 这种非导出字段。必须在启动时显式打开模块访问权限:
立即学习“Java免费学习笔记(深入)”;
java --add-opens java.base/sun.misc=ALL-UNNAMED YourApp
- 如果用的是 JDK 16+,还得加
--illegal-access=permit(但该参数已在 JDK 17 彻底移除) - Maven 插件或 IDE 运行配置里漏掉这个参数,
Field.setAccessible(true)也会静默失败,不报错但返回 null - Gradle 用户注意:
jvmArgs必须写在runtask 里,不是compileJava
真正难的不是调通那几行 Unsafe 代码,而是你没法保证这段逻辑在 JDK 11、17、21 上行为一致——字段名可能改、校验逻辑可能加、甚至整个类被移到 jdk.internal.misc 包下。拿它做业务逻辑,等于把系统命脉绑在 JVM 内部实现上。


















