類型指針
一般對象指針(oop, ordinary object pointer)是HotSpot虛擬機的一個術語,表示受托管的對象指針。它的大小通常和本地指針是一樣的。Java應用程序和GC子系統會非常小心地跟蹤這些受托管的指針,以便在銷毀對象時回收內存空間,或是在對空間進行整理時移動(復制)對象。
為什么要壓縮指針
類型指針是對象指向它的類的元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。並不是所有的虛擬機實現都必須在對象數據上保留類型指針,換句話說查找對象的元數據信息並不一定要經過對象本身。 以前的是32位,也就說內存的尋址空間最大可以達到2的32次方的地址,2的32次方表示的地址空間是4G ,但是現在很多內存大小都超過了4G , 在64位的java虛擬機中,類型指針占了64位,位數的增加雖然可以尋址到更大的空間,但是實際上我們並沒有使用那么大的空間了,並且位數增加了意味這占用更大的內存,也是就說64位的類型指針位數太多了。 也就是我只要能表示該地址就行了。於是就出現了如下
oops 最后的三位始終為零。這樣可想而知,有些地址不能表示了,因為它的尾3位都是0,所以需要對齊。
什么情況下會進行壓縮?
下面表述摘自 http://shzhangji.com/cnblogs/2015/06/25/compressed-oops-in-the-hotspot-jvm/ 如果UseCompressedOops是打開的,則以下對象的指針會被壓縮:
- 所有對象的klass屬性
- 所有對象指針實例的屬性
- 所有對象指針數組的元素(objArray) HotSpot VM中,用於表示Java類的數據結構是不會壓縮的,這部分數據都存放在永久代(PermGen)中。
在解釋器中,一般對象指針也是不壓縮的,包括JVM本地變量和棧內元素、調用參數、返回值等。解釋器會在讀取堆內對象時解碼對象指針,並在存入時進行編碼。
同樣,方法調用序列(method calling sequence),無論是解釋執行還是編譯執行,都不會使用對象指針壓縮。
在編譯后的代碼中,對象指針是否壓縮取決於不同的優化結果。優化后的代碼可能會將壓縮后的對象指針直接從一處搬往另一處,而不進行編解碼操作。如果芯片(如x86)支持解碼,那在使用對象指針時就不需要自行解碼了。
所以,以下數據結構在編譯后的代碼中既可以是壓縮后的對象指針,也可能是本地地址:
- 寄存器或溢出槽(spill slot)中的數據
- 對象指針映射表(GC映射表)
- 調試信息
- 嵌套在機器碼中的對象指針(在非RISC芯片中支持,如x86)
- nmethod常量區(包括那些影響到機器碼的重定位操作)
補充
使用 jol 來查看對象頭的信息
增加依賴
<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.10</version> </dependency>
Object object = new Object(); String info = ClassLayout.parseClass(Object.class).toPrintable(object); System.out.println("info : " + info); 結果 : java.lang.Object 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) e5 c1 f2 27 (11100101 11000001 11110010 00100111) (670220773) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
參考資料
- http://shzhangji.com/cnblogs/2015/06/25/compressed-oops-in-the-hotspot-jvm/(推薦閱讀)
- https://docs.oracle.com/cd/E19620-01/805-3024/lp64-1/index.html(32和64位下C語言數據結構位數的表示)
- https://wiki.openjdk.java.net/display/HotSpot/CompressedOops(推薦閱讀)