Java 内存分区之什么是 CCS区 Compressed Class Space 类压缩空间

了解到什么是ccs区,一般都是实际执行了jstat -gc 之后,看Java堆的gc相关的几个分区的gc信息,前面的s0,s1,e区,o区,还好猜,研究过分区的,不难猜出来这个分区是啥意思,M区虽然不知道是Metaspace元空间,但是错把这个M区当成Method area 方法区,也说的过去。这个ccsc就不好说了。之前的看的文章都没人说这个区是啥。

Java之jstat的用法:Java虚拟机 统计信息查看 工具

不了解这几个简写单词是啥意思的,可以参考一下之前的这个jstat的文章,里面对每一列的title的简写都做了解释。

什么是 Compressed Class Space

在 64 位平台上,HotSpot 使用了两个压缩优化技术,Compressed Object Pointers (“CompressedOops”) 和 Compressed Class Pointers。
压缩指针,指的是在 64 位的机器上,使用 32 位的指针来访问数据(堆中的对象或 Metaspace 中的元数据)的一种方式。
这样有很多的好处,比如 32 位的指针占用更小的内存,可以更好地使用缓存,在有些平台,还可以使用到更多的寄存器。
当然,在 64 位的机器中,最终还是需要一个 64 位的地址来访问数据的,所以这个 32 位的值是相对于一个基准地址的值。

下面将描述 Compressed Class Pointers

每个 Java 对象,在它的头部,有一个引用指向 Metaspace 中的 Klass 结构。

Java 内存分区之什么是 CCS区 Compressed Class Space 类压缩空间_第1张图片

当使用了 compressed class pointers,这个引用是 32 位的值,为了找到真正的 64 位地址,需要加上一个 base 值:

Java 内存分区之什么是 CCS区 Compressed Class Space 类压缩空间_第2张图片

上面的内容应该很好理解,这项技术对 Klass 的分配带来的问题是:由于 32 位地址只能访问到 4G 的空间,所以最大只允许 4G 的 Klass 地址。这项限制也意味着,JVM 需要向 Metaspace 分配一个连续的地址空间

当从系统申请内存时,通过调用系统接口 malloc(3) 或 mmap(3),操作系统可能返回任意一个地址值,所以在 64位系统中,它并不能保证在 4G 的范围内。

所以,我们只能用一个 mmap() 来申请一个区域单独用来存放 Klass 对象。我们需要提前知道这个区域的大小,而且不能超过 4G。显然,这种方式是不能扩展的,因为这个地址后面的内存可能是被占用的。

只有 Klass 结构有这个限制,对于其他的 class metadata 没有这个必要: 因为只有 Klass 实例是通过 Java 对象 header 中的压缩指针访问的。其他的 metadata 都是通过 64 位的地址进行访问的,所以它们可以被放到任意的地址上。

所以,我们决定将 Metaspace 分为两个区域:non-class part 和 class part。

  • class part:存放 Klass 对象,需要一个连续的不超过 4G 的内存
  • non-class part:包含其他的所有 metadata

class part 被称作 Compressed Class Space,这个名字会有点怪,因为 Klass 本身其实没有使用压缩技术,而是引用它们的指针被压缩了。

compressed class space 空间的大小,是通过 -XX:CompressedClassSpaceSize 指定的。

我们需要提前知道自己需要多少内存,它的默认值是 1G。当然这个 1G 并不是真的使用了操作系统的 1G,而是虚拟地址映射。

开关: UseCompressedClassPointers, UseCompressedOops

-XX:+UseCompressedOops 允许对象指针压缩。

-XX:+UseCompressedClassPointers 允许类指针压缩。

它们默认都是开启的,可以手动关闭它们。

如果不允许类指针压缩,那么将没有 compressed class space 这个空间,并且-XX:CompressedClassSpaceSize 这个参数无效。

-XX:-UseCompressedClassPointers 需要搭配 -XX:+UseCompressedOops,但是反过来不是: 我们可以只压缩对象指针,不压缩类指针。

这里面为什么这么规定我也不懂,但是从直觉上来说,压缩对象指针显然是比较重要的,能获得较大的收益。也许就是基于这种考量吧:你连对象指针都不压缩,类指针压缩不压缩又有什么关系呢?

注意,对象指针压缩要求堆小于 32G,所以如果堆大于等于 32G,那么对象指针压缩和类指针压缩都会被关闭。

再多的消化不了拉。

参考:

深入理解堆外内存 Metaspace

你可能感兴趣的:(jvm,java,jdk,操作系统)