轉載請註明原創出處,謝謝! 問題 這個Xmn設置為1G,,我用jmap heap 看,這個Eden From To怎麼不是一個整8:1:1的關係呢? 我看記憶體分配還是沒變,我Xmn1g,感覺From、To應該都是102.4M才對,現在是102.375M。 執行命令 結果: 發現很奇怪,的確和我們相信 ...
轉載請註明原創出處,謝謝!
問題
這個Xmn設置為1G,,我用jmap -heap 看,這個Eden From To怎麼不是一個整8:1:1的關係呢?
我看記憶體分配還是沒變,我Xmn1g,感覺From、To應該都是102.4M才對,現在是102.375M。
執行命令
jstat -gc pid 1s 1
結果:
發現很奇怪,的確和我們相信的不一樣,我覺得只有源碼可以告訴我們他做了啥。查看源碼:
執行上面的例子代碼
public static void main(String[] args) {
System.out.println(107374183&~((1<<16)-1));
}
輸出結果為:
107347968
104832K * 1024剛剛好等於107347968B
R大以前的回覆:
從該信息中可以得到:Oracle/Sun JDK及OpenJDK里的HotSpot VM的話預設GC堆里的對象用8位元組對齊。
java記憶體參數對齊問題
上面問題其實就是java記憶體參數對齊問題。那麼為什麼需要java記憶體參數對齊問題?
記憶體對齊(Data Structure Alignment)是什麼?
記憶體對齊,或者說位元組對齊,是一個數據類型所能存放的記憶體地址的屬性(Alignment is a property of a memory address)。這個屬性是一個無符號整數,並且這個整數必須是2的N次方(1、2、4、8、……、1024、……)。當我們說,一個數據類型的記憶體對齊為8時,意思就是指這個數據類型所定義出來的所有變數,其記憶體地址都是8的倍數。當一個基本數據類型(fundamental types)的對齊屬性,和這個數據類型的大小相等時,這種對齊方式稱作自然對齊(naturally aligned)。比如,一個4位元組大小的int型數據,預設情況下它的位元組對齊也是4。
為什麼我們需要記憶體對齊?
這是因為,並不是每一個硬體平臺都能夠隨便訪問任意位置的記憶體的。
微軟的MSDN里有這樣一段話:
Many CPUs, such as those based on Alpha, IA-64, MIPS, and SuperH architectures, refuse to read misaligned data. When a program requests that one of these CPUs access data that is not aligned, the CPU enters an exception state and notifies the software that it cannot continue. On ARM, MIPS, and SH device platforms, for example, the operating system default is to give the application an exception notification when a misaligned access is requested.
大意是說,有不少平臺的CPU,比如Alpha、IA-64、MIPS還有SuperH架構,若讀取的數據是未對齊的(比如一個4位元組的int在一個奇數記憶體地址上),將拒絕訪問,或拋出硬體異常。
另外,在維基百科里也記載著如下內容:
Data alignment means putting the data at a memory offset equal to some multiple of the word size, which increases the system's performance due to the way the CPU handles memory.
意思是,考慮到CPU處理記憶體的方式(32位的x86 CPU,一個時鐘周期可以讀取4個連續的記憶體單元,即4位元組),使用位元組對齊將會提高系統的性能(也就是CPU讀取記憶體數據的效率。比如你一個int放在奇數記憶體位置上,想把這4個位元組讀出來,32位CPU就需要兩次。但對齊之後一次就可以了)。
- 需要位元組對齊的根本原因在於CPU訪問數據的效率問題。假設上面整型變數的地址不是自然對齊,比如為0x00000002,則CPU如果取它的值的話需要訪問兩次記憶體,第一次取從0x00000002-0x00000003的一個short,第二次取從0x00000004-0x00000005的一個short然後組合得到所要的數據,如果變數在0x00000003地址上的話則要訪問三次記憶體,第一次為char,第二次為short,第三次為char,然後組合得到整型數據。
- 而如果變數在自然對齊位置上,則只要一次就可以取出數據。一些系統對對齊要求非常嚴格,比如sparc系統,如果取未對齊的數據會發生錯誤,而在x86上就不會出現錯誤,只是效率下降。
- 各個硬體平臺對存儲空間的處理上有很大的不同。一些平臺對某些特定類型的數據只能從某些特定地址開始存取。
- 比如有些架構的CPU在訪問一個沒有進行對齊的變數的時候會發生錯誤,那麼在這種架構下編程必須保證位元組對齊,但其他平臺可能沒有這種情況,但是最常見的是如果不按照適合其平臺要求對數據存放進行對齊,會在存取效率上帶來損失。
- 比如有些平臺每次讀都是從偶地址開始,如果一個int型(假設為32位系統)如果存放在偶地址開始的地方,那麼一個讀周期就可以讀出這32bit,而如果存放在奇地址開始的地方,就需要2個讀周期,並對兩次讀出的結果的高低位元組進行拼湊才能得到該32bit數據。顯然在讀取效率上下降很多。
- 另外位元組對齊的作用不僅是==便於cpu快速訪問==,同時合理的利用位元組對齊可以==有效地節省存儲空間==。
- 也即CPU一次訪問時,要麼讀0x01~0x04,要麼讀0x05~0x08…硬體不支持一次訪問就讀到0x02~0x05
- 例:如果0x02~0x05存了一個int,讀取這個int就需要先讀0x01~0x04,留下0x02~0x04的內容,再讀0x05~0x08,留下0x05的內容,兩部分拼接起來才能得到那個int的值,這樣讀一個int就要兩次記憶體訪問,效率就低了。
個人公眾號
參考:
https://www.2cto.com/kf/201407/319682.html
http://blog.csdn.net/qq_25077833/article/details/53454958