Java 9中压缩string和压缩string的区别

JDK9中压缩string的紧凑string的优点是什么?

压缩的string(Java 6)和紧凑的string(Java 9)都有相同的动机(string通常是有效的Latin-1,所以浪费了一半的空间)和目标(使这些string很小),但实现方式有很大的不同。

压缩的string

在接受采访时, AlekseyShipilëv(负责实现Java 9特性)对压缩string这样说:

UseCompressedStringsfunction相当保守:在区分char[]byte[]情况下,试图在String构造中将char[]压缩为byte[]时,它对char[]进行了大部分的String操作,这需要解压缩String. 因此,只有特殊types的工作负载才能受益,大多数string都是可压缩的(所以压缩不会浪费),并且只对其执行有限的已知String操作(因此不需要拆包)。 在许多工作负载中,启用-XX:+UseCompressedStrings是一个悲观的事情。

UseCompressedStrings实现基本上是一个可选的function,它在alt-rt.jar中维护了一个完全不同的String实现,一旦VM选项被提供,该实现就被加载。 可选function很难testing,因为它们使选项组合的数量加倍来尝试。

紧凑的string

另一方面,在Java 9中,紧凑的string完全集成到JDK源代码中。 String 总是byte[]支持,其中字符使用一个字节,如果他们是拉丁-1,否则两个。 大多数操作做一个检查,看看是哪种情况,例如charAt

 public char charAt(int index) { if (isLatin1()) { return StringLatin1.charAt(value, index); } else { return StringUTF16.charAt(value, index); } } 

压缩string是默认启用的,可以部分禁用 – “部分”,因为它们仍然由byte[]支持,并且返回char的操作仍然必须将它们从两个单独的字节放在一起(由于内在的原因,很难说这是否是对性能有影响)。

更多

如果你对紧凑弦乐有更多的背景感兴趣,我build议阅读我上面链接的采访内容 ,或者用同样的AlekseyShipilëv (这也解释了新的string连接)来观看这个伟大的演讲 。

XX:+ UseCompressedStrings紧凑string是不同的东西。

UseCompressedStrings意味着只有ASCII的string可以被转换为byte[] ,但是这是默认closures的。 在jdk-9中,这种优化总是处于开启状态,但不是通过标志本身,而是内置的。

直到java-9string以UTF-16编码forms存储在char[]中。 从java-9开始,它们将被存储为byte[] 。 为什么?

因为在ISO_LATIN_1每个字符可以用一个字节(8位)进行编码,直到现在(16位,每个字节从未使用过8位)为止。 这只适用于ISO_LATIN_1 ,但这是大部分string使用。

这样做是为了空间使用。

这是一个小例子,应该让事情更清楚:

 class StringCharVsByte { public static void main(String[] args) { String first = "first"; String russianFirst = "первыи"; char[] c1 = first.toCharArray(); char[] c2 = russianFirst.toCharArray(); for (char c : c1) { System.out.println(c >>> 8); } for (char c : c2) { System.out.println(c >>> 8); } } } 

在第一种情况下,我们只能得到零,这意味着最重要的8位是零; 在第二种情况下,会有一个非零值,意味着至less有一位来自最重要的8位。

这意味着如果在内部我们将string存储为一个字符数组,实际上会浪费一半字符的string文字。 事实certificate,有多个应用程序实际上因此浪费了很多空间。

你有一个由10个Latin1字符组成的string? 你只丢了80位,或10​​个字节。 为了缓解这个String压缩做了。 而现在,这些弦乐将不会有空间损失。

在内部这也意味着一些非常好的事情。 要区分LATIN1UTF-16string,有一个字段coder

 /** * The identifier of the encoding used to encode the bytes in * {@code value}. The supported values in this implementation are * * LATIN1 * UTF16 * * @implNote This field is trusted by the VM, and is a subject to * constant folding if String instance is constant. Overwriting this * field after construction will cause problems. */ private final byte coder; 

现在根据这个length计算不同:

 public int length() { return value.length >> coder(); } 

如果我们的string只是Latin1,那么编码器将变为零,所以值的长度(字节数组)就是字符的大小。 非拉丁文1除以2。

紧凑string将有两全其美。

从OpenJDK文档中提供的定义可以看出:

新的String类将根据string的内容存储以ISO-8859-1 / Latin-1(每个字符一个字节)或UTF-16(每个字符两个字节)编码的字符。 编码标志将指示使用哪种编码。

正如@Eugene所提到的,大多数string都以Latin-1格式编码,每个字符需要一个字节,因此不需要当前String类实现中提供的整个2字节空间。

新的String类实现将从UTF-16 char array转换a byte array 加上一个编码标志字段 。 额外的编码字段将显示是否使用UTF-16或Latin-1格式存储字符。

这也可以得出结论,如果需要,我们也可以存储UTF-16格式的string。 这也成为压缩string中Java 6的 压缩string和Java 9压缩string之间的区别的主要点, 只有byte []数组用于存储,然后表示为纯ASCII

压缩string (-XX:+ UseCompressedStrings)

这是Java 6 Update 21中引入的一个可选function,通过在每个字符的字节上仅编码US-ASCIIstring来提高SPECjbb性能。

该function可以通过-XX标志( -XX:+UseCompressedStrings )来启用。 当它被启用时, String.value被更改为一个Object引用,并指向byte[] ,仅包含7位US-ASCII字符的string或char[]

后来在Java 7中被删除,因为维护量很高,很难testing。

紧凑string

这是Java 9中引入的一个新特性,用于构build一个高效的内存string。

在Java 9之前,String类存储字符数组中的字符,每个字符使用两个字节,但是从Java 9开始,新的String类将以byte[] (每个字符一个字节)或char[] (每个字符两个字节),根据string的内容,加上一个编码标志字段。 如果string字符是Latin-1types,那么如果字符是UTF-16types,将使用byte[]那么将使用char[] 。 编码标志将指示使用哪种编码。