Java 9中压缩字符串和压缩字符串的区别
JDK9中压缩字符串的优点是什么?XX:+use压缩字符串和压缩字符串是不同的Java 9中压缩字符串和压缩字符串的区别,java,string,java-9,Java,String,Java 9,JDK9中压缩字符串的优点是什么?XX:+use压缩字符串和压缩字符串是不同的 UseCompressedStrings意味着只能将ASCII字符串转换为字节[],但默认情况下这是关闭的。在jdk-9中,此优化始终处于启用状态,但不是通过标志本身,而是内置的 直到java-9字符串在UTF-16编码中作为char[]存储在内部。在java-9及以上版本中,它们将存储为字节[]。为什么? 因为在ISO_LATIN_1中,每个字符都可以用一个字节(8位)编码,而到目前为止(16位,其中8位从未使用过
UseCompressedStrings
意味着只能将ASCII字符串转换为字节[]
,但默认情况下这是关闭的。在jdk-9中,此优化始终处于启用状态,但不是通过标志本身,而是内置的
直到java-9字符串在UTF-16编码中作为char[]
存储在内部。在java-9及以上版本中,它们将存储为字节[]
。为什么?
因为在ISO_LATIN_1
中,每个字符都可以用一个字节(8位)编码,而到目前为止(16位,其中8位从未使用过)。这只适用于ISO_LATIN_1
,但这是大多数使用的字符串
这就是空间利用率
下面是一个小例子,可以让事情变得更清楚:
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位是零;在第二种情况下,将有一个非零值,这意味着从最高有效8中至少有一位存在
这意味着,如果我们在内部将字符串存储为一个字符数组,那么实际上存在浪费每个字符一半的字符串文本。事实证明,有多个应用程序实际上因此浪费了大量空间
你有一个由10个拉丁文1字符组成的字符串吗?您刚刚丢失了80位或10字节。为了减轻这种压力,进行了字符串压缩。现在,这些字符串将不会丢失空间
在内部,这也意味着一些非常好的事情。要区分LATIN1
和UTF-16
字符串,有一个字段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;
现在根据此长度
的计算方式不同:
public int length() {
return value.length >> coder();
}
如果我们的字符串仅为Latin1,则编码器将为零,因此值的长度(字节数组)是字符的大小。对于非拉丁语,1除以2。紧凑型字符串将两全其美
从OpenJDK文档中提供的定义中可以看出:
新的String类将根据字符串的内容存储编码为ISO-8859-1/Latin-1(每个字符一个字节)或UTF-16(每个字符两个字节)的字符。编码标志将指示使用哪种编码
正如@Eugene所提到的,大多数字符串是以拉丁-1格式编码的,每个字符需要一个字节,因此不需要当前字符串类实现中提供的整个2字节空间
新的字符串类实现将从UTF-16字符数组
转换为字节数组
加上编码标志字段。附加编码字段将显示字符是使用UTF-16还是拉丁-1格式存储的
这还表明,如果需要,我们还可以以UTF-16格式存储字符串。这也成为Java 6的压缩字符串和Java 9的压缩字符串之间的主要区别,因为在压缩字符串中,只有字节[]数组用于存储,然后表示为纯ASCII 压缩字符串(Java 6)和压缩字符串(Java 9)都有相同的动机(字符串通常是有效的拉丁语-1,因此浪费了一半的空间)和目标(使这些字符串变小),但实现方式有很大不同
压缩字符串
在Aleksey Shipilëv(负责实现Java 9特性)中,他对压缩字符串有这样的看法:
UseCompressedStrings特性相当保守:在区分char[]
和byte[]
大小写的同时,尝试将char[]
压缩为byte[]
字符串的String
构造上的String
操作,它需要解包字符串。
因此,它只对一种特殊类型的工作负载有利,其中大多数字符串是可压缩的(因此压缩不会浪费),并且只对它们执行有限数量的已知字符串
操作(因此不需要解包)。在很多工作负载中,启用-XX:+UseCompressedStrings
是一种悲观情绪
[…]UseCompressedStrings实现基本上是一个可选功能,它在alt-rt.jar
中维护了一个完全不同的String
实现,该实现在提供VM选项后加载。可选功能更难测试,因为它们将要尝试的选项组合数量增加了一倍
紧弦
另一方面,在Java9中,压缩字符串完全集成到JDK源代码中String
始终以byte[]
为后盾,其中字符使用一个字节(如果是拉丁语-1),否则使用两个字节。大多数操作都会检查哪种情况,例如charAt
:
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
压缩字符串在默认情况下是启用的,并且可以部分禁用-“部分”因为它们仍然由字节[]
支持,并且返回char
s的操作仍然必须从两个单独的字节将它们放在一起(由于内部特性,很难说这是否会影响性能)
更多
如果您对压缩字符串的更多背景信息感兴趣,我建议您阅读我在上面链接的内容和/或观看(这也解释了新的字符串连接)。压缩字符串(-XX:+UseCompressedStrings) 这是Java6Update 21中引入的可选功能,通过在每个字符的字节上只编码US-ASCII字符串来提高性能 此功能可通过
-XX
标志(-XX:+UseCompressedStrings
)启用。启用时,String.value
被更改为对象引用,对于仅包含7位US-ASCII的字符串,它将指向字节[]