compact strings相对于JDK9中的压缩字符串有什么优势?
答案 0 :(得分:70)
压缩字符串(Java 6)和紧凑字符串(Java 9)都具有相同的动机(字符串通常有效地为Latin-1,因此浪费了一半的空间)和目标(使这些字符串变小)但实现不同很多。
在an interviewAlekseyShipilëv(负责实现Java 9功能)中有关于压缩字符串的说法:
UseCompressedStrings功能相当保守:在区分
char[]
和byte[]
的情况下,并尝试将char[]
压缩为byte[]
构建String
时完成String
上的大多数char[]
操作,这需要解压缩String.
因此,它只能使特殊类型的工作负载受益,其中大多数字符串都是可压缩的(因此压缩不会浪费) ,并且只对它们执行有限数量的已知String
操作(因此不需要解包)。在很多工作负载中,启用-XX:+UseCompressedStrings
是一种悲观情绪。[...] UseCompressedStrings实现基本上是一个可选功能,它在
String
中维护了一个完全不同的alt-rt.jar
实现,它在提供VM选项后加载。可选功能更难测试,因为它们会使选项组合的数量增加一倍。
另一方面,在Java 9中,紧凑字符串完全集成到JDK源中。 String
始终支持byte[]
,其中字符使用一个字节(如果它们是Latin-1),否则使用两个字节。大多数操作都会检查以查看是哪种情况,例如: charAt
:
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
默认情况下启用紧凑字符串,可以部分禁用 - “部分”,因为它们仍然由byte[]
支持,返回char
的操作必须仍然将它们从两个单独的字节放在一起(到期)对于内在函数,很难说这是否会对性能产生影响。)
如果您对更多关于紧凑字符串的背景感兴趣,我建议您阅读the interview我链接到上面和/或观看this great talk by the same Aleksey Shipilëv(这也解释了新的字符串连接)。
答案 1 :(得分:23)
XX:+ UseCompressedStrings 和 Compact Strings 是不同的东西。
UseCompressedStrings
意味着只有ASCII的字符串可以转换为byte[]
,但默认情况下这是关闭的。在jdk-9中,这种优化始终是开启的,但不是通过标志本身,而是内置。
直到java-9字符串在内部存储为UTF-16编码的char[]
。从java-9开始,它们将存储为byte[]
。为什么呢?
因为在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个Latin1字符组成的字符串?你只丢了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;
现在基于此length
的计算方式不同:
public int length() {
return value.length >> coder();
}
如果我们的String只是Latin1,则编码器将为零,因此值的长度(字节数组)是字符的大小。对于非拉丁语1除以2。
答案 2 :(得分:7)
Compact Strings 将拥有两全其美的优势。
从OpenJDK文档中提供的定义中可以看出:
新的String类将根据字符串的内容存储编码为ISO-8859-1 / Latin-1(每个字符一个字节)或UTF-16(每个字符两个字节)的字符。编码标志将指示使用的编码。
正如@Eugene所提到的,大多数字符串都是用Latin-1格式编码的,每个字符需要一个字节,因此不需要在当前的String类实现中提供整个2字节空间。
新的String类实现将从UTF-16 char array
转换为a byte array
加上encoding-flag字段。附加的编码字段将显示字符是使用UTF-16还是Latin-1格式存储。
这也得出结论,如果需要,我们还能够以UTF-16格式存储字符串。这也成为压缩字符串Java 6 和 Compact String of Java 9 之间的主要区别点,如压缩字符串 only byte [] array 用于存储,然后表示为纯ASCII 。
答案 3 :(得分:0)
压缩字符串(-XX:+ UseCompressedStrings)
这是 Java 6 更新21中引入的可选功能,通过在每个字符的字节上仅编码US-ASCII字符串来提高SPECjbb性能。
此功能可以通过-XX
标记(-XX:+UseCompressedStrings
)启用。启用后,String.value
已更改为Object引用,并指向byte[]
,表示仅包含7位US-ASCII字符的字符串,或者char[]
。
后来它在Java 7中被删除了,因为维护费用高且难以测试。
紧凑字符串
这是 Java 9 中引入的一项新功能,用于构建内存高效的String。
在Java 9之前,String类在char数组中存储了字符,每个字符使用两个字节,但是从Java 9开始,新的String类将在byte[]
(每个字符一个字节)或{{1}中存储字符(每个字符两个字节),基于字符串的内容,加上encoding-flag字段。如果字符串字符属于char[]
类型,则如果字符属于Latin-1
类型,则将使用byte[]
,然后将使用UTF-16
。编码标志将指示使用的编码。