一般64位JVM消耗的內存會比32位的大1.5倍,這是由於對象指針在64位架構下,長度會翻倍(更寬的尋址)。
對於那些將要從32位平臺移植到64位的應用來講,平白無辜多了1/2的內存佔用,這是開發者不肯意看到的。
幸運的是,從JDK 1.6 update14開始,64 bit JVM正式支持了 -XX:+UseCompressedOops 這個能夠壓縮指針,起到節約內存佔用的新參數。java
OOP = 「ordinary object pointer」 普通對象指針。數組
啓用CompressOops後,會壓縮的對象:
• 每一個Class的屬性指針(靜態成員變量)
• 每一個對象的屬性指針
• 普通對象數組的每一個元素指針架構
固然,壓縮也不是萬能的,針對一些特殊類型的指針,JVM是不會優化的。
好比指向PermGen的Class對象指針,本地變量,堆棧元素,入參,返回值,NULL指針不會被壓縮。ide
在啓動java時,加 -XX:+UseCompressedOops (須要jdk1.6.0_14)oop
原理,解釋器在解釋字節碼時,植入壓縮指令(不影響正常和JVM優化後的指令順序)。
具體邏輯是,當對象被讀取時,解壓,存入heap時,壓縮。優化
壓縮指令僞碼spa
! int R8; oop[] R9; // R9 is 64 bits
! oop R10 = R9[R8]; // R10 is 32 bits
! load compressed ptr from wide base ptr:
movl R10, [R9 + R8<<3 + 16]
! klassOop R11 = R10._klass; // R11 is 32 bits
! void* const R12 = GetHeapBase();
! load compressed klass ptr from compressed base ptr:
movl R11, [R12 + R10<<3 + 8]指針
零基壓縮是針對壓解壓動做的進一步優化。
它經過改變正常指針的隨機地址分配特性,強制從零開始作分配(須要OS支持),進一步提升了壓解壓效率。對象
要啓用零基壓縮,你分配給JVM的內存大小必須控制在4G以上,32G如下。
若是小於4G,那麼JVM會使用低虛擬地址空間(low virutal address space,64位下模擬32位),這樣就不須要作壓解壓動做了。
而對於大於32G,將採用默認的隨機地址分配特性,進行壓解壓。內存
CompressedOops,能夠讓跑在64位平臺下的JVM,不須要由於更寬的尋址,而付出Heap容量損失的代價。不過,它的實現方式是在機器碼中植入壓縮與解壓指令,可能會給JVM增長額外的開銷。