2012-06-02 57 views
4

X86-64,Linux,Windows。將內存映射到另一個地址

考慮一下,我想做一些「標籤指針自由啓動」。基本上我想有兩個指針指向相同的實際內存塊,但其位是不同的。 (例如,我希望一位被GC收集使用或出於某種其他原因)。

intptr_t ptr = malloc() 
intptr_t ptr2 = map(ptr | GC_FLAG_REACHABLE) //some magic call 

int* p = int*(ptr); 
int* p2 = int*(ptr2); 
*p = 10; 
*p2 = 20; 
assert(*p == 20) 
assert(p != p2) 

回答

2

在Linux上,mmap()同一個文件兩次。在Windows上同樣的事情,但它有它自己的一套功能。

1

曾幾何時我曾在一個Prolog的實現,使用以下技術有一個指針備用位:

  • 分配存儲區域,並已知對齊。 malloc()通常以4字節或8字節對齊方式分配內存。如有必要,請使用posix_memalign()獲取更高對齊大小的區域。由於生成的指針與多個字節的間隔對齊,但它表示字節準確的地址,因此您有一些備用位,根據定義,它將在內存區指針中爲零。例如,一個4字節的對齊會在指針的LSB端提供兩個備用位。

  • 您或(|)您的標誌與這些位,現在有一個標記的指針。

  • 只要你在使用內存訪問之前注意正確地遮罩指針,你應該會很好。

2

映射相同的內存(在POSIX mmap作爲伊格納西奧提到,MapViewOfFile在Windows上)到多個虛擬地址可以提供你一些有趣的一致性難題(當在另一地址讀取是在一個地址可見寫?)。或者可能不是。我不確定所有的平臺保證是什麼。

更普遍的是,只需在指針中保留幾位並根據需要進行移動。

如果所有對象都對齊到8字節的邊界,通常只需將標記存儲在指針的3個最低有效位中,並在解引用之前屏蔽它們(如提到的那樣)。如果您選擇更高的對齊方式,例如16字節或32字節,則可以使用3或5個最低有效位進行標記。等同地,選擇幾個最重要的位進行標記,並在解除引用之前關閉它們。 (包裝指針到IEEE-754浮點數(2個23個值)或雙打(2個51個值)的信號NaN時有時不連續的比特被使用,例如。)

繼續在高端的指針,x86-64的當前實現在64位指針(0x0000000000000000-0x00007fffffffffff + 0xffff800000000000-0xffffffffffffffff)中最多使用48位,並且Linux和Windows僅將用戶空間的第一範圍中的地址分發給用戶空間,有效位可以被安全地屏蔽掉。 (雖然這不是可移植的也不保證在將來保持真實。)

另一種方法是停止考慮「指針」,並簡單地將索引用於更大的內存數組,因爲JVM使用-XX:+UseCompressedOops。如果您已經分配了一個512MB池並存儲了8字節對齊的對象,則可能有對象位置,因此除索引外,32值還有6位可用。解引用將需要將索引乘以對齊到數組的基址,並保存在別處(每個「指針」都是一樣的)。如果你仔細看看,這只是對先前技術的總結(它總是以0爲基礎,其中事物與真實指針對齊)。

相關問題