类型指针
一般对象指针(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(推荐阅读)