JVM之压缩指针(CompressedOops)

栏目: C · 发布时间: 7年前

内容简介:对于32位机器,进程能使用的最大内存是4G。如果进程需要使用更多的内存,需要使用64位机器。对于Java进程,在oop只有32位时,只能引用4G内存。因此,如果需要使用更大的堆内存,需要部署64位JVM。这样,oop为64位,可引用的堆内存就更大了。注:oop(ordinary object pointer),即普通对象指针,是JVM中用于代表引用对象的句柄。

对于32位机器,进程能使用的最大内存是4G。如果进程需要使用更多的内存,需要使用64位机器。

对于 Java 进程,在oop只有32位时,只能引用4G内存。因此,如果需要使用更大的堆内存,需要部署64位JVM。这样,oop为64位,可引用的堆内存就更大了。

注:oop(ordinary object pointer),即普通对象指针,是JVM中用于代表引用对象的句柄。

在堆中,32位的对象引用占4个字节,而64位的对象引用占8个字节。也就是说,64位的对象引用大小是32位的2倍。

64位JVM在支持更大堆的同时,由于对象引用变大却带来了性能问题:

  1. 增加了GC开销

64位对象引用需要占用更多的堆空间,留给其他数据的空间将会减少,从而加快了GC的发生,更频繁的进行GC。

  1. 降低CPU缓存命中率

64位对象引用增大了,CPU能缓存的oop将会更少,从而降低了CPU缓存的效率。

为了能够保持32位的性能,oop必须保留32位。那么,如何用32位oop来引用更大的堆内存呢?

答案是压缩指针(CompressedOops)。

JVM的实现方式是,不再保存所有引用,而是每隔8个字节保存一个引用。例如,原来保存每个引用0、1、2...,现在只保存0、8、16...。因此,指针压缩后,并不是所有引用都保存在堆中,而是以8个字节为间隔保存引用。

在实现上,堆中的引用其实还是按照0x0、0x1、0x2...进行存储。只不过当引用被存入64位的寄存器时,JVM将其左移3位(相当于末尾添加3个0),例如0x0、0x1、0x2...分别被转换为0x0、0x8、0x10。而当从寄存器读出时,JVM又可以右移3位,丢弃末尾的0。(oop在堆中是32位,在寄存器中是35位,2的35次方=32G。也就是说,使用32位,来达到35位oop所能引用的堆内存空间)

JVM之压缩指针(CompressedOops)

在JVM中(不管是32位还是64位),对象已经按8字节边界对齐了。对于大部分处理器,这种对齐方案都是最优的。所以,使用压缩的oop并不会带来什么损失,反而提升了性能。

Oracle JDK从6 update 23开始在64位系统上会默认开启压缩指针。

32位HotSpot VM是不支持UseCompressedOops参数的,只有64位HotSpot VM才支持。

对于大小在4G和32G之间的堆,应该使用压缩的oop。

查看压缩指针的工作模式

在VM启动的时候,可以设置 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode 参数来确认压缩指针的工作模式。

JDK 7

压缩指针默认开启:

$ java -server -Xms2G -Xmx2G -XX:+UseConcMarkSweepGC -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version

heap address: 0x000000077ae00000, size: 2130 MB, zero based Compressed Oops

java version "1.7.0_79"
Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)
复制代码

JDK 8

压缩指针默认开启:

$ java -server -Xms2G -Xmx2G -XX:+UseConcMarkSweepGC -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version

heap address: 0x0000000080000000, size: 2048 MB, Compressed Oops mode: 32-bit

Narrow klass base: 0x0000000000000000, Narrow klass shift: 3
Compressed class space size: 1073741824 Address: 0x000000013fe20000 Req Addr: 0x0000000100000000
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
复制代码

关闭压缩指针:

$ java -server -Xms2G -Xmx2G -XX:+UseConcMarkSweepGC -XX:-UseCompressedOops -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
复制代码

实例比较

测试环境:JDK 1.8.0_121

测试代码

import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class IntegerApplication {
	public static void main(String[] args) {
		List<Integer> intList = new LinkedList<>();
		for (int i = 0; i < 2000000; i++) {
			Integer number = new Integer(1);
			intList.add(number);
		}
		Scanner scanner = new Scanner(System.in);
		System.out.println("application is running...");
		String tmp = scanner.nextLine();
		System.exit(0);
	}
}
复制代码

使用Eclipse Memory Analyzer查看Integer对象数量与大小

先运行程序IntegerApplication,再通过mat查看对象分配情况。

JVM之压缩指针(CompressedOops)
JVM之压缩指针(CompressedOops)
JVM之压缩指针(CompressedOops)

开启压缩指针

压缩指针默认开启(-XX:+UseCompressedOops)。

$ java IntegerApplication
application is running...
复制代码
JVM之压缩指针(CompressedOops)

每个Integer大小为:

64(Mark Word)+32(Compressed oops)+32(int)=128bits=16bytes

所有Integer总大小为:

2000256*16=32004096bytes

关闭压缩指针

设置参数-XX:-UseCompressedOops,关闭压缩指针。

$ java -XX:-UseCompressedOops IntegerApplication
application is running...
复制代码
JVM之压缩指针(CompressedOops)

每个Integer大小为:

64(Mark Word)+64(Compressed oops)+32(int)=160bits=20bytes

由于JVM内存分配需要根据字宽进行对齐,对于64位JVM,字宽为8个字节。因此,一个Integer实际占用24bytes,即192bits。

所有Integer总大小为:

2000256*24=48006144bytes

通过上面的实例可以看到,在开启压缩指针之后,oop大小确实是变成了32位,并且实际测试结果与理论分析是一致的。


以上所述就是小编给大家介绍的《JVM之压缩指针(CompressedOops)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Purely Functional Data Structures

Purely Functional Data Structures

Chris Okasaki / Cambridge University Press / 1999-6-13 / USD 49.99

Most books on data structures assume an imperative language such as C or C++. However, data structures for these languages do not always translate well to functional languages such as Standard ML, Ha......一起来看看 《Purely Functional Data Structures》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具