现在基本上已经是 64 位机的时代了,内存单元的地址也是 64 位。
在 Java 中,除了 8 种基本类型,最常见的类型就是引用类型了,引用类型封装了引用对象的指针。使用压缩指针将 64 位长度的指针压缩到 32 位,可以有效降低存储空间的开销。
压缩指针
首先它不是一个地址,它是一个相对于堆 64 位基址上的一个偏移量。由于对象大小一定是 8 字节的整数倍,所以这个偏移量的单位不是字节,而是 8 字节。
CompressedOops 转换成地址:ObjectAddress64 = BaseAddress64 + 8*CompressedOops。
注:oops 是 Ordinary Object Pointers 的缩写。
CompressedOops 偏移量的单位如果是字节,寻址范围是 4 GB,那么实际上的寻址范围为 32 GB。(RAM 存储器的编址以字节为单位。)
所以如果堆大小大于 32 GB,压缩指针就不能用了,只能老老实实的使用 64 位的指针。
Java SE 6u23 和更高版本默认情况下支持并启用压缩指针。在 Java SE 7 中,对于未设置 -Xmx 参数或 -Xmx 设置小于 32 GB 的 64 位 JVM 进程中,默认使用压缩指针。对于在 6u23 发行版之前的 JDK 6,使用 -XX:+UseCompressedOops 启用压缩指针。
零基压缩指针
JVM 进程可以请求操作系统把堆的基址分配在虚地址为 0 的位置,那么 CompressedOops 转换成地址,就成了:ObjectAddress64 = 8*CompressedOops,少了一个加法操作。
如果堆大小小于 4 GB,还可以去掉 8 的缩放,再少一个乘法操作。压缩指针直接取 64 位地址的低 32 位即可。
官方文档里说:对于大小约为 26g 的 Java 堆,任何 Solaris、Linux 和 Windows 操作系统通常都能够在虚拟地址 0 处分配 Java 堆。
网友评论