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

时间:2017-05-25 10:38:21

标签: java string java-9

compact strings相对于JDK9中的压缩字符串有什么优势?

4 个答案:

答案 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​​个字节。为了缓解这种字符串压缩。而现在,这些弦乐将不会有空间损失。

在内部,这也意味着一些非常好的东西。要区分LATIN1UTF-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。编码标志将指示使用的编码。