在傳統 Java 開發中,開發者無需直接操作記憶體位址。但若想深入理解 JVM 物件模型、進行效能調優或實作底層框架,獲取物件的記憶體位移資訊至關重要。本文介紹如何利用 sun.misc.Unsafe 繞過安全檢查,獲取欄位在物件中的偏移量。
sun.misc.Unsafe 提供底層記憶體操作能力,包含直接記憶體存取、CAS 原子操作、執行緒調度等。其建構子為私有,需透過反射獲取單例實例。注意:此類屬於 JDK 內部 API,版本間可能變動,生產環境謹慎使用。
private static Unsafe getUnsafeInstance() throws Exception {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(Unsafe.class);
}
objectFieldOffset(Field f):回傳實例欄位在物件中的偏移量(相對於物件起始位址)。staticFieldOffset(Field f):回傳靜態欄位在類別記憶體區域的偏移量。這些偏移量並非絕對物理位址,而是 JVM 內部的邏輯位移,配合 Unsafe 的 getInt、putInt、getObject 等方法可直接讀寫欄位值,繞過 Java 存取控制。
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class ObjectLocation {
private static int apple = 10; // 靜態欄位
private int orange = 10; // 實例欄位
public static void main(String[] args) throws Exception {
Unsafe unsafe = getUnsafeInstance();
Field appleField = ObjectLocation.class.getDeclaredField("apple");
System.out.println("Location of Apple (static): " + unsafe.staticFieldOffset(appleField));
Field orangeField = ObjectLocation.class.getDeclaredField("orange");
System.out.println("Location of Orange (instance): " + unsafe.objectFieldOffset(orangeField));
}
private static Unsafe getUnsafeInstance() throws Exception {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(Unsafe.class);
}
}
| 方法 | 說明 |
|---|---|
compareAndSwapInt(Object obj, long offset, int expect, int update) | CAS 更新 int 欄位,成功回傳 true |
compareAndSwapObject(Object obj, long offset, Object expect, Object update) | CAS 更新物件參考 |
objectFieldOffset(Field f) | 獲取實例欄位偏移量 |
staticFieldOffset(Field f) | 獲取靜態欄位偏移量 |
getInt(Object obj, long offset) | 讀取指定偏移量的 int 值 |
putInt(Object obj, long offset, int value) | 寫入指定偏移量的 int 值 |
getObject(Object obj, long offset) | 讀取指定偏移量的物件參考 |
park(boolean isAbsolute, long time) | 阻塞當前執行緒 |
unpark(Thread thread) | 喚醒指定執行緒 |
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED。java.lang.invoke.VarHandle 提供標準化、安全的欄位存取與 CAS 能力,建議優先使用。透過 Unsafe 可窺探 JVM 物件佈局,理解欄位偏移、記憶體對齊等底層機制。雖然日常開發罕見直接使用,但對於研發高效能並發框架、序列化庫、記憶體分析工具的開發者而言,掌握其原理極具價值。