Java 9 中压缩字符串和压缩字符串之间的区别
在 JDK9 中,与压缩字符串相比,紧凑字符串有哪些优势?
压缩字符串(Java 6)和压缩字符串(Java 9)都有相同的动机(字符串通常是有效的拉丁语-1,所以一半的空间被浪费了)和目标(使这些字符串变小),但实现差异很大。
在一次采访中,Aleksey Shipilëv(负责实现Java 9功能)对压缩字符串有这样的看法:
UseCompressedStrings功能相当保守:在区分和大小写的同时,并试图在构造上压缩,它完成了大多数操作,这需要解压缩因此,它只受益于一种特殊类型的工作负载,其中大多数字符串是可压缩的(因此压缩不会浪费),并且只对它们执行有限数量的已知操作(因此不需要解压缩)。在许多工作负载中,启用是一种悲观。
char[]
byte[]
char[]
byte[]
String
String
char[]
String.
String
-XX:+UseCompressedStrings
[...]UseCompressedStrings 实现基本上是一个可选功能,它维护了 一个完全不同的实现,一旦提供了 VM 选项,就会加载该实现。可选功能更难测试,因为它们使要尝试的选项组合数量增加了一倍。
String
alt-rt.jar
另一方面,在Java 9中,紧凑的字符串完全集成到JDK源代码中。 始终由 支持,其中字符使用一个字节(如果它们是拉丁语-1),否则使用两个字节。大多数操作都会进行检查以查看哪种情况,例如:String
byte[]
charAt
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
默认情况下,紧凑字符串处于启用状态,并且可以部分禁用 - “部分”,因为它们仍由 a 支持,返回 s 的操作仍必须将它们从两个单独的字节放在一起(由于内部函数,很难说这是否对性能有影响)。byte[]
char
如果你对紧凑字符串的更多背景感兴趣,我建议你阅读我上面链接的采访和/或观看同一位Aleksey Shipilëv的精彩演讲(这也解释了新的字符串串联)。
XX:+UseCompressedStrings和Compact Strings是不同的东西。
UseCompressedStrings
意味着只有 ASCII 的字符串可以转换为 ,但默认情况下这是关闭的。在jdk-9中,这种优化始终处于打开状态,但不是通过标志本身,而是内置的。byte[]
直到 java-9 字符串以 UTF-16 编码的形式存储在内部。从java-9及更高版本开始,它们将被存储为.为什么?char[]
byte[]
因为每个字符都可以编码为单个字节(8位),而它曾经是直到现在(16位,每个8位从未使用过)。这仅适用于 ,但这是大多数使用的字符串。ISO_LATIN_1
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中的至少一位。
这意味着,如果我们在内部将 Strings 存储为字符数组,则存在实际上会浪费每个 char 的一半的字符串文本。事实证明,由于这个原因,有多个应用程序实际上浪费了大量空间。
您有一个由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;
现在基于此计算方式不同:length
public int length() {
return value.length >> coder();
}
如果我们的字符串只是 Latin1,则编码器将为零,因此值的长度(字节数组)是字符的大小。对于非拉丁语1除以2。