Nic*_*lai 71
压缩字符串(Java 6)和紧凑字符串(Java 9)都具有相同的动机(字符串通常有效地为Latin-1,因此浪费了一半空间)和目标(使这些字符串变小)但实现方式差别很大.
在一次采访中, AlekseyShipilë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[]
,在字符使用一个字节,如果他们是拉丁语-1否则两项.大多数操作都会检查以查看是哪种情况,例如charAt
:
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
Run Code Online (Sandbox Code Playgroud)
紧凑字符串默认启用,可以部分禁用 - "部分",因为它们仍然由a支持byte[]
和操作返回char
s必须仍然将它们从两个单独的字节放在一起(由于内在函数,很难说这是否会影响性能).
如果你对更多关于紧凑字符串的背景感兴趣,我建议你阅读我上面链接的访谈和/或观看同一个AlekseyShipilëv的精彩演讲(这也解释了新的字符串连接).
Eug*_*ene 24
XX:+ UseCompressedStrings和Compact Strings是不同的东西.
UseCompressedStrings
意味着只能转换为ASCII的字符串byte[]
,但默认情况下这是关闭的.在jdk-9中,这种优化始终是开启的,但不是通过标志本身,而是内置.
直到java-9字符串在内部存储为char[]
UTF-16编码.从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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,我们将仅获得零,这意味着最重要的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;
Run Code Online (Sandbox Code Playgroud)
现在基于此length
计算方式不同:
public int length() {
return value.length >> coder();
}
Run Code Online (Sandbox Code Playgroud)
如果我们的String只是Latin1,则编码器将为零,因此值的长度(字节数组)是字符的大小.对于非拉丁语1除以2.
Compact Strings将拥有两全其美.
从OpenJDK文档中提供的定义可以看出:
新的String类将存储根据字符串内容编码为ISO-8859-1/Latin-1(每个字符一个字节)或UTF-16(每个字符两个字节)的字符.编码标志将指示使用哪种编码.
正如@Eugene所提到的,大多数字符串都是用Latin-1格式编码的,每个字符需要一个字节,因此不需要在当前的String类实现中提供整个2字节空间.
新的String类的实现将转移UTF-16 char array
到a byte array
加编码标记字段.附加编码字段将显示是使用UTF-16还是Latin-1格式存储字符.
这也得出结论,如果需要,我们还能够以UTF-16格式存储字符串.而这也成为之间差异的主要点的Java 6的压缩字符串和爪哇9的紧凑字符串作为压缩字符串仅byte []数组被用于存储,然后将其作为representated 纯ASCII.
归档时间: |
|
查看次数: |
5505 次 |
最近记录: |