Unsafe:查看版本 v4
由 mcst12345 于 2026-10-04 04:16 保存 · 3889 字节
'''Unsafe'''(<code>sun.misc.Unsafe</code>,*Java9+ 位于 <code>jdk.unsupported</code> 模块)提供直接内存读写、字段偏移、CAS、不经构造器创建对象等底层操作,绕过 Java 的访问检查和类型安全。自Java9開始<code>sun.misc.Unsafe</code>為<code>jdk.internal.misc.Unsafe</code>的封裝。
== 获取 ==
构造器私有,通常用 [[Reflection]] 读取静态字段 <code>theUnsafe</code>:
<code>Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe u = (Unsafe) f.get(null);</code>
== 常用能力 ==
* <code>objectFieldOffset</code> / <code>staticFieldBase</code> / <code>staticFieldOffset</code> 配合 <code>getObject</code>、<code>putObject</code>、<code>getInt</code>、<code>putInt</code> 等:直接读写任意字段,包括 <code>final</code> 字段。
* <code>allocateInstance</code>:不调用构造器创建对象。
* <code>compareAndSwap*</code> / <code>getAndSet*</code>:原子操作。
* <code>allocateMemory</code> / <code>freeMemory</code> / <code>getAddress</code> / <code>putAddress</code>:堆外内存。
* 读写对象头:[[klassptr]] 就是用 <code>getInt</code> / <code>putInt</code> 改写对象头里的类型指针,从而改变对象在 JVM 眼中的类型。
* 读取 <code>MethodHandles.Lookup.IMPL_LOOKUP</code> 等 JDK 内部静态字段,见 [[MethodHandle]]。
* 修改 Klass 内部标志:例如清除[[隐藏类]]的 hidden 标志,使它被当作普通类,从而能被 [[retransformClasses]] / [[redefineClasses]] 处理;依赖 JDK 内部布局,不同版本需要适配。
== 局限 ==
* 偏移量或地址写错可能会直接导致非法內存訪問。
* 对 record 和隐藏类的字段,<code>objectFieldOffset</code> 会抛异常。
* <code>defineClass</code> ,<code>defineAnonymousClass</code> 已於 JDK 11/17 移除並遷移至 <code>MethodHandles.Lookup</code>。
* JDK 23 起,<code>sun.misc.Unsafe</code> 的内存访问方法被标记为弃用待删除(JEP 471)。
'''Unsafe''' class is mainly used for raw memory access. Before Java 9 there's only <code>sun.misc.Unsafe</code>, after that <code>sun.misc.Unsafe</code> has became a wrapper for <code>jdk.internal.misc.Unsafe</code>
== Capability ==
Unsafe can be used to read/write most primitive types from/to a specific memoy address through methods like getInt(long), putInt(long,int). There are also volatile variants like getIntVolatile and putIntVolatile. There are also oop variants such as getInt(Object,long) to access memory based on the address of a Java object, which can be used to access object fields. There's objectFieldOffset and staticFieldOffset methods to obtain offset of object/static fields. For static field there's a staticFieldBase method to obtain the "base" object when accessing static fields, however it's just the field's declaring class so that you can just use field.getDeclaringClass() instead. There's also getReference/getObject/putReference/putObject (the name depends on your Java version) to fetch/write Java objects.
Unsafe can also be used to manage off-heap memory using allocateMemory,freeMemory,reallocateMemory methods.
Unsafe.allocateInstance(Class) can be used to allocate a Java object without invoking <init> which means that the object is uninitialized.
Unsafe also supports CAS operations. There are many *compareAndSet* methods.
arrayBaseOffset and arrayIndexScale are used to access Java array using Unsafe. arrayBaseOffset returns the offset of the first element of a Java array based on the array object itself, arrayIndexScale returns the size of each element for an array type.
//TODO
== Notes ==
* Unsafe is marked for deprecated for a long time, though it has never been removed. However it has changed significantly that most of its apis aren't persistent across Java versions.
* An illegal memory access will crash JVM.