unsafe.objectfieldoffset()返回字段相对于对象起始地址的字节偏移量,用于高性能字段访问;需传入非static非final的field对象,配合setaccessible(true),且偏移量依赖jvm运行时布局,不可硬编码。

Unsafe.objectFieldOffset 用于获取某个类中指定 非静态成员变量 相对于对象起始地址的内存偏移量(单位:字节),是 JVM 底层操作的关键工具之一,常用于高性能框架(如 Netty、Disruptor)或自定义序列化/反射优化中。
前提条件:必须能访问 Unsafe 实例
Java 9+ 默认禁止直接使用 Unsafe,需通过反射绕过限制(仅限开发/测试环境,生产慎用):
- 先通过
Unsafe.getUnsafe()尝试获取(JDK 8 可行,JDK 9+ 多数情况会抛SecurityException) - 更通用的方式是用反射读取私有静态字段
theUnsafe:
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
目标字段必须是非 static、非 final(JDK 8 及以前可绕过 final,JDK 9+ 更严格)
该方法只对实例字段有效。static 字段没有对象内偏移,final 字段在某些 JDK 版本中可能被 JIT 优化为常量,导致偏移不可靠或方法抛出 IllegalArgumentException。
- 确保字段声明为
public / protected / package-private(private 也可,但需配合反射设为 accessible) - 字段不能是
static,否则objectFieldOffset会返回 0 或抛异常 - JDK 17+ 对 final 字段限制更强,建议测试时用非 final 字段验证
调用方式:传入 Field 对象,不是字段名字符串
不能直接传字段名,必须先通过 Class.getDeclaredField(String) 获取 Field 对象,再传给 objectFieldOffset:
- 字段名拼写、大小写必须完全匹配,否则抛
NoSuchFieldException - 记得调用
setAccessible(true)(尤其 private 字段) - 返回值是 long 类型的偏移量,通常为正整数(如 12、16、24 等,取决于 JVM 对象布局和字段顺序)
class TestObj {
int x;
long y;
}
Field xField = TestObj.class.getDeclaredField("x");
xField.setAccessible(true);
long offset = unsafe.objectFieldOffset(xField); // 如返回 12
注意对象内存布局受 JVM 参数影响
偏移量不是固定值,它依赖于:
- JVM 位数(32/64 位)和是否开启压缩指针(
-XX:+UseCompressedOops) - 字段声明顺序、类型大小、JVM 的字段重排序策略(如按大小升序排列以减少填充)
- 是否启用分代压缩、对象头结构等底层细节
因此,偏移量应在运行时动态获取,不可硬编码;不同 JVM 配置下结果可能不同。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











