我想提取一些研究目的的java對象的實際地址。爲了清楚起見,我實際上需要對象的48位虛擬地址,而不是ID或散列碼或任何唯一標識符,並且我明白這些地址是由GC移動的。我一直在閱讀其他帖子,比如here或here。Java對象地址提取和驗證
對於以下我使用@Peter Lawrey -> Is there a way to get a reference address?方法。所以它使用Unsafe
類和arrayBaseOffset
方法。我對這些方法感到奇怪的是,他們給出了每次運行(至少在我的電腦上)相同的結果,這是不太可能發生的。由於安全原因,內存分配應該是隨機的。
此外,我試圖驗證這些方法與Pintools這是英特爾的儀器工具,我用來提取運行的內存痕跡。我的問題是,我無法將我在Pintools的內存跟蹤中看到的內容與上述方法給出的地址相關聯以獲取內存地址。我的內存跟蹤中永遠不會訪問給定的地址。
所以我想知道這些方法返回的是什麼,以及這些結果如何與其他工具進行驗證。
一些相關信息:我的操作系統是Ubuntu的x86_64的,我的JVM是OpenJDK的64位1.8.0_131,pintools版本是V3.2
================ === 大編輯:我意識到,我的問題沒有得到很好的說,所以讓我獲得了更多的原子例如,這裏是我嘗試分析了java:
`import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class HelloWorld {
public static void main(String[] args) throws Exception {
Unsafe unsafe = getUnsafeInstance();
Integer i = new Integer(42);
long addr_fromArray;
long addr_fromObject;
/////////////////////////////////////
Object[] objects = {i};
long baseOffset = unsafe.arrayBaseOffset(Object[].class);
addr_fromArray = unsafe.getLong(objects, baseOffset);
long factor1 = 8;
long addr_withFactor = (unsafe.getInt(objects, baseOffset) & 0xFFFFFFFFL) * factor1;
/////////////////////////////////////
class Pointer {
Object pointer;
}
Pointer pointer = new Pointer();
pointer.pointer = i;
long offset = unsafe.objectFieldOffset(Pointer.class.getDeclaredField("pointer"));
addr_fromObject = unsafe.getLong(pointer, offset);
System.out.println("Addr of i from Array : 0x" + Long.toHexString(addr_fromArray));
System.out.println("Addr of i from Object : 0x" + Long.toHexString(addr_fromObject));
System.out.println("Addr of i from factor1 : 0x" + Long.toHexString(addr_withFactor));
System.out.println("!=1");//Launch the pintools instrumentation
for(int a= 0 ; a < 123 ;a++){
i = 10;
}
System.out.println("!=1");//Stop the pintools instrumentation
}
private static Unsafe getUnsafeInstance() throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeInstance.setAccessible(true);
return (Unsafe) theUnsafeInstance.get(Unsafe.class);
}
}`
我得到的指針我從堆棧溢出中看到的不同方法的整數。然後,我在一個循環中對任意數量的時間進行循環,以便我可以在我的記憶痕跡中識別出它(注意:我檢查了此代碼中沒有發生GC調用)
當pintools看到特定的「!= 1」寫在標準輸出,啓動/停止儀器
在在儀表階段每次訪問,我執行此代碼:
VOID RecordAccess(VOID* ip, int id_thread , VOID * addr, int id)
{
PIN_GetLock(&lock, id_thread);
if(startInstru)
{
log1 << "Data accessed: " << addr << "\tThread:" << id_thread << endl;
nb_access++;
uint64_t dummy = reinterpret_cast<uint64_t>(addr);
if(accessPerAddr.count(dummy) == 0)
accessPerAddr.insert(pair<uint64_t,uint64_t>(dummy, 0));
accessPerAddr[dummy]++;
}
}
有了這個pintools,我產生記憶痕跡+如何一個直方圖多次訪問每個存儲器地址。 注意:pintool是通過「follow_execv」選項啓動的,以便測試每個線程。
我看到2個問題:
1)我認爲沒有訪問到任何印刷我地址(或接近此地址)。我傾向於信任Pintools,因爲我以前使用過很多,但也許Pintools無法在此處檢索到正確的地址。
2)我看不到地址被訪問123次(或接近此)。我的想法是,也許JVM在這裏執行優化,因爲它看到執行的代碼沒有效果,所以它不執行它。然而,我嘗試了一個更復雜的指令(不能像存儲一個隨機數那樣優化),而不僅僅是一個商店,而沒有更好的結果。
我不在乎這裏的GC效應,可能在第二步。我只想從我的Java應用程序中提取本地地址,我很確定Pintools給我的。
您可能想要包含您的代碼 –
'由於安全原因,內存分配應該是隨機分配的。'。你有任何參考這實際發生在Java?這個語句在C中有一定的意義,緩衝區溢出可能導致代碼執行。 –
添加了一些代碼,如果這有幫助! –