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压缩做了。 而现在,这些弦乐将不会有空间损失。
在内部这也意味着一些非常好的事情。 要区分LATIN1
和UTF-16
string,有一个字段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-1
types,那么如果字符是UTF-16
types,将使用byte[]
那么将使用char[]
。 编码标志将指示使用哪种编码。