2016-02-15 34 views
4

所以,我試圖運行一些簡單的代碼,JDK-8,輸出通過約爾java8 -XX:+ UseCompressedOops -XX:ObjectAlignmentInBytes = 16

System.out.println(VMSupport.vmDetails()); 
    Integer i = new Integer(23); 
    System.out.println(ClassLayout.parseInstance(i) 
      .toPrintable()); 

第一次嘗試與運行在64位JVM上也禁用壓縮的oops和壓縮klass。

-XX:-UseCompressedOops -XX:-UseCompressedClassPointers 

輸出,幾乎預期是:

Running 64-bit HotSpot VM. 
Objects are 8 bytes aligned. 

java.lang.Integer object internals: 
OFFSET SIZE TYPE DESCRIPTION     VALUE 
    0  4  (object header)    01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
    4  4  (object header)    00 00 00 00 (00000000 00000000 00000000 00000000) (0) 
    8  4  (object header)    48 33 36 97 (01001000 00110011 00110110 10010111) (-1758055608) 
12  4  (object header)    01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
16  4 int Integer.value     23 
20  4  (loss due to the next object alignment) 

Instance size: 24 bytes (reported by Instrumentation API) 
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 

這是有道理的:8個字節克拉斯字+ 8字節標記字+ 4個字節的實際值和4填充(對齊在8個字節上)= 24個字節。

第二次嘗試在64位JVM上使用壓縮的oops啓用壓縮的klass。

同樣,輸出是非常理解的:

Running 64-bit HotSpot VM. 
Using compressed oop with 3-bit shift. 
Using compressed klass with 3-bit shift. 
Objects are 8 bytes aligned. 

OFFSET SIZE TYPE DESCRIPTION     VALUE 
    0  4  (object header)    01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
    4  4  (object header)    00 00 00 00 (00000000 00000000 00000000 00000000) (0) 
    8  4  (object header)    f9 33 01 f8 (11111001 00110011 00000001 11111000) (-134138887) 
12  4 int Dummy.i      42 
Instance size: 16 bytes (reported by Instrumentation API). 

4字節的壓縮接力(克拉斯字)+ 8個字節標記字+ 4個爲值+沒有空間損耗= 16個字節字節。

是沒有意義對我來說,事情是這樣的用例:

-XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:ObjectAlignmentInBytes=16 

輸出是這樣的:

Running 64-bit HotSpot VM. 
Using compressed oop with 4-bit shift. 
Using compressed klass with 0x0000001000000000 base address and 0-bit shift. 

我真的很期待都爲「4位移「。他們爲什麼不是?

編輯 第二個例子是與運行:

XX:+UseCompressedOops -XX:+UseCompressedClassPointers 

,第三個用:

-XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:ObjectAlignmentInBytes=16 

回答

3

我會盡量延長Alexey提供的答案,因爲有些事情可能並不明顯。

繼阿列克謝建議,如果我們搜索的OpenJDK對需要壓縮克拉斯移位值分配的源代碼,我們會發現在metaspace.cpp下面的代碼:

void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address cds_base) { 
// some code removed 
if ((uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) { 
    Universe::set_narrow_klass_shift(0); 
} else { 
    assert(!UseSharedSpaces, "Cannot shift with UseSharedSpaces"); 
    Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes); 
} 

正如我們所看到的,類移可以是0(或基本上沒有偏移)或3位,因爲LogKlassAlignmentInBytes是在globalDefinitions.hpp定義的常數:

const int LogKlassAlignmentInBytes = 3; 

所以,回答您quetion

我真的希望都是「4位移位」。他們爲什麼不是?

是ObjectAlignmentInBytes對始終爲8字節的元空間中的壓縮類指針對齊沒有任何影響。

當然,這個結論不回答這個問題:

「使用-XX時爲什麼:ObjectAlignmentInBytes = 16 -XX:+ UseCompressedClassPointers狹窄克拉斯轉變爲零而且不轉移如何能在JVM使用32位引用引用類空間,如果堆是4GB或更多?「

我們已經知道,類空間是分配在java堆的頂部,可以達到3G的大小。考慮到這一點,我們來做一些測試。 -XX:+ UseCompressedOops -XX:+ UseCompressedClassPointers是默認啓用的,所以我們可以簡化它們。

測試1:默認值 - 8個字節對齊

$ java -XX:ObjectAlignmentInBytes=8 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version 

heap address: 0x00000006c0000000, size: 4096 MB, zero based Compressed Oops 

Narrow klass base: 0x0000000000000000, Narrow klass shift: 3 
Compressed class space size: 1073741824 Address: 0x00000007c0000000 Req Addr: 0x00000007c0000000 

注意,在堆地址0x00000006c0000000在虛擬空間中開始,並且具有大小4GBytes的的。讓我們從堆開始的地方跳4Gbytes,然後我們降落到課程空間開始的地方。

0x00000006c0000000 + 0x0000000100000000 = 0x00000007c0000000 

類空間大小爲1GB的,讓我們用另一種1GB的跳躍:

0x00000007c0000000 + 0x0000000040000000 = 0x0000000800000000 

和我們的土地略低於32Gbytes。使用3位的類空間移位,JVM能夠引用整個類空間,儘管它處於有限的範圍內(有意)。

測試2:16個字節對齊

java -XX:ObjectAlignmentInBytes=16 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version 

heap address: 0x0000000f00000000, size: 4096 MB, zero based Compressed Oops 

Narrow klass base: 0x0000001000000000, Narrow klass shift: 0 
Compressed class space size: 1073741824 Address: 0x0000001000000000 Req Addr: 0x0000001000000000 

這個時候我們可以看到,堆的地址是不同的,但讓我們嘗試相同的步驟:

0x0000000f00000000 + 0x0000000100000000 = 0x0000001000000000 

這一次堆空間結束於64GBytes的虛擬空間邊界之下,並且類空間被分配在64Gbyte邊界之上。由於類空間只能使用3位移位,因此JVM如何引用位於64G字節以上的類空間?最關鍵的是:

Narrow klass base: 0x0000001000000000 

的JVM仍然使用32位壓縮指針爲類的空間,但是,當編碼和解碼這些,它將始終0x0000001000000000鹼添加到壓縮的基準,而不是使用移位。請注意,只要引用的內存塊低於4Gbytes(對32位引用的限制),此方法就可以工作。考慮到班級空間最多可以有3Gbytes,我們很容易就能達到這個限度。

3:16個字節對齊,在8克

$ java -XX:ObjectAlignmentInBytes=16 -XX:HeapBaseMinAddress=8g -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version 

heap address: 0x0000000200000000, size: 4096 MB, zero based Compressed Oops 

Narrow klass base: 0x0000000000000000, Narrow klass shift: 3 
Compressed class space size: 1073741824 Address: 0x0000000300000000 Req Addr: 0x0000000300000000 

銷堆鹼在該測試中,我們仍然保持-XX:ObjectAlignmentInBytes = 16,而且還要求JVM於在分配堆在虛擬地址空間中使用-XX:HeapBaseMinAddress = 8g JVM參數的第8個GByte。類空間將在虛擬地址空間中以12 GByte開始,3位移位足以引用它。

希望這些試驗及其結果回答這個問題:

「爲什麼使用-XX時:ObjectAlignmentInBytes = 16 -XX:+ UseCompressedClassPointers窄克拉斯移變爲零而且,不轉移如何能如果堆是4GBytes或更多,JVM引用32位引用的類空間?「

+0

迷人!非常清楚。 – Eugene

5

這些問題的答案尋找到OpenJDK的代碼時,大多是很容易弄清楚。

例如,grep命令 「UseCompressedClassPointers」,這將讓你arguments.cpp

// Check the CompressedClassSpaceSize to make sure we use compressed klass ptrs. 
if (UseCompressedClassPointers) { 
    if (CompressedClassSpaceSize > KlassEncodingMetaspaceMax) { 
    warning("CompressedClassSpaceSize is too large for UseCompressedClassPointers"); 
    FLAG_SET_DEFAULT(UseCompressedClassPointers, false); 
    } 
} 

好,有趣,有 「CompressedClassSpaceSize」? grep命令的定義,它在globals.hpp

product(size_t, CompressedClassSpaceSize, 1*G,       \ 
      "Maximum size of class area in Metaspace when compressed "  \ 
      "class pointers are used")          \ 
      range(1*M, 3*G)             \ 

啊哈,因此該類區域是在元空間中,它1 MB和空間的3 Gb之間發生某處。讓我們用grep爲「CompressedClassSpaceSize」的用法,因爲這會帶我們去處理它實際的代碼,說在metaspace.cpp

// For UseCompressedClassPointers the class space is reserved above 
// the top of the Java heap. The argument passed in is at the base of 
// the compressed space. 
void Metaspace::initialize_class_space(ReservedSpace rs) { 

因此,壓縮類是在Java堆之外小班空間,不分配需要移位 - 即使是3千兆字節也足夠小,只能使用最低的32位。

+0

這是一個很好的解釋,但還有一些我希望通過你的幫助進一步理解的細節。因此,元組空間中存在一個空間(我知道它是堆外的),名爲CompressedClassSpace,它的最大尺寸是3G,而32位則足以引用這些3G,因此不需要移位,對吧?如果是這樣,那麼爲什麼你仍然在第二個例子呢? – Eugene

+2

AFAIU,沒有'UseCompressedClassPointers'類鏡像仍然分配在堆上,並且對它們的引用被壓縮爲對其他對象的引用。這就是爲什麼他們需要3位移位,就像其他普通的Java對象一樣。 –

+0

謝謝!非常感激。 – Eugene

相關問題