首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

探秘 Java 物件記憶體位址:基於 sun.misc.Unsafe 的實戰分析

     編輯:Java 程式設計入門

前言

在傳統 Java 開發中,開發者無需直接操作記憶體位址。但若想深入理解 JVM 物件模型、進行效能調優或實作底層框架,獲取物件的記憶體位移資訊至關重要。本文介紹如何利用 sun.misc.Unsafe 繞過安全檢查,獲取欄位在物件中的偏移量。

Unsafe 類別簡介

sun.misc.Unsafe 提供底層記憶體操作能力,包含直接記憶體存取、CAS 原子操作、執行緒調度等。其建構子為私有,需透過反射獲取單例實例。注意:此類屬於 JDK 內部 API,版本間可能變動,生產環境謹慎使用。

獲取 Unsafe 實例

private static Unsafe getUnsafeInstance() throws Exception {
    Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    theUnsafe.setAccessible(true);
    return (Unsafe) theUnsafe.get(Unsafe.class);
}

核心方法:objectFieldOffset 與 staticFieldOffset

  • objectFieldOffset(Field f):回傳實例欄位在物件中的偏移量(相對於物件起始位址)。
  • staticFieldOffset(Field f):回傳靜態欄位在類別記憶體區域的偏移量。

這些偏移量並非絕對物理位址,而是 JVM 內部的邏輯位移,配合 Unsafe 的 getInt、putInt、getObject 等方法可直接讀寫欄位值,繞過 Java 存取控制。

完整範例程式碼 (適用 JDK 1.6+)

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);
    }
}

Unsafe 常用 API 速查

方法說明
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)喚醒指定執行緒

注意事項與替代方案

  • 安全性:Unsafe 繞過 JVM 安全檢查,錯誤使用會導致 JVM 崩潰或資料損毀。
  • 可移植性:內部 API 不保證跨版本相容,JDK 9+ 模組化後需加啟動參數 --add-exports java.base/jdk.internal.misc=ALL-UNNAMED。
  • 現代替代:JDK 9 引入 java.lang.invoke.VarHandle 提供標準化、安全的欄位存取與 CAS 能力,建議優先使用。

結語

透過 Unsafe 可窺探 JVM 物件佈局,理解欄位偏移、記憶體對齊等底層機制。雖然日常開發罕見直接使用,但對於研發高效能並發框架、序列化庫、記憶體分析工具的開發者而言,掌握其原理極具價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved