2011-08-14 48 views

回答

27

這是你可能不想做的事情。

如果你真的要做到這一點,像這樣的代碼可能會有所幫助:

package test; 

import java.lang.reflect.Field; 

import sun.misc.Unsafe; 

public class Addresser 
{ 
    private static Unsafe unsafe; 

    static 
    { 
     try 
     { 
      Field field = Unsafe.class.getDeclaredField("theUnsafe"); 
      field.setAccessible(true); 
      unsafe = (Unsafe)field.get(null); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 

    public static long addressOf(Object o) 
    throws Exception 
    { 
     Object[] array = new Object[] {o}; 

     long baseOffset = unsafe.arrayBaseOffset(Object[].class); 
     int addressSize = unsafe.addressSize(); 
     long objectAddress; 
     switch (addressSize) 
     { 
      case 4: 
       objectAddress = unsafe.getInt(array, baseOffset); 
       break; 
      case 8: 
       objectAddress = unsafe.getLong(array, baseOffset); 
       break; 
      default: 
       throw new Error("unsupported address size: " + addressSize); 
     }  

     return(objectAddress); 
    } 


    public static void main(String... args) 
    throws Exception 
    { 
     Object mine = "Hi there".toCharArray(); 
     long address = addressOf(mine); 
     System.out.println("Addess: " + address); 

     //Verify address works - should see the characters in the array in the output 
     printBytes(address, 27); 

    } 

    public static void printBytes(long objectAddress, int num) 
    { 
     for (long i = 0; i < num; i++) 
     { 
      int cur = unsafe.getByte(objectAddress + i); 
      System.out.print((char)cur); 
     } 
     System.out.println(); 
    } 
} 

  • 不能跨越的JVM甚至不同版本
  • 對象可以因爲移動便攜的GC,無法在GC之間同步,因此結果可能不合理
  • 未測試交流羅斯所有的架構,字節順序等可能使這個不行到處
+1

即使UseCompressedOpps處於打開狀態,64位Sun JDK上的'unsafe.addressSize()'似乎也會返回8。使用'unsafe.arrayIndexScale(Object []。class)',在這種情況下返回4,似乎更有可能使用這種技術(畢竟,您將對象存儲在Object數組中)。 對於壓縮的oops,返回的地址不是真正的地址 - 它可能會右移3位,等等。 – BeeOnRope

9

如果不使用特定於JVM的功能,則無法執行此操作。 Java有意隱藏與每個對象相關聯的位置,從而爲實現提供更大的靈活性(JVM通常在執行垃圾回收時在內存中移動對象)並提高安全性(不能使用原始指針來垃圾內存或訪問不存在的對象)。

+0

那麼Object.hashCode()的默認實現呢?它返回對象的內存地址,不是嗎?它使用@prunge告訴的不安全類嗎?我知道這是一個本地方法,所以也許這只是C++中的一個指針到int的轉換? –

+1

'Object.hashCode()'不會*返回對象的內存地址。它是特定於實現的。我花了好幾個月的時間研究一個JVM的JavaScript實現,在這裏你不能使用原始地址,只需要爲每個對象增加一個計數器來實現Object.hashCode()。在一些實現中,這可能是'Object.hashCode()'的工作原理,但是由於許多JVM在內存中移動對象,所以你不能依賴這一點。 – templatetypedef

+0

'System.identityHashcode(Object)'比返回對象的內存地址複雜得多,即使這看起來是這樣。首先,即使GC移動了對象,它也必須返回相同的值。這通常需要*保存*對象中的值。 (有些JVM以一種聰明的方式來做到這一點,從而最大限度地減少開銷......但最終還是會付錢的。) –

-2

我想知道JVM分配給對象

你不能的位置,因爲它不存在。由於垃圾收集器的動作,它會隨着時間而改變。 「位置」沒有這種東西。

+2

我的信用卡餘額變化,不幸的是它們仍然存在。 – weston

+1

@weston您的信用卡餘額發生變化,因此您不能依賴它始終保持不變。 – EJP

+1

他們沒有說他們需要依靠它而不改變。我的觀點(笑話)並不意味着它不存在。但無論如何有辦法將它釘住:JNI關鍵部分,例如位置確切並且保證不變。 – weston

-1

您可以使用http://openjdk.java.net/projects/code-tools/jol解析對象佈局。對於一個對象,你可以使用:

System.out.println(
    GraphLayout.parseInstance(someObject).toPrintable()); 
+0

a)僅鏈接答案在這裏不被認爲是很好的答案,請參閱[答案]。 b)這個問題已經有其他幾個高質量的答案;這添加了什麼? – EJoshuaS

+0

感謝您的反饋。它增加了對標準現代工具JOL的參考,這些不在這裏。更清潔和便攜的方式,這爲作者的任務取一行代碼,而不是不安全的例子。我還爲這個問題添加了代碼示例。 – egorlitvinenko

相關問題