Java 9中压缩字符串和压缩字符串的区别

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位从未使用过

JDK9中压缩字符串的优点是什么?

XX:+use压缩字符串和压缩字符串是不同的

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的字符串,它将指向
字节[]