web-dev-qa-db-ja.com

Java 9のコンパクト文字列と圧縮文字列の違い

コンパクト文字列 のJDK9での圧縮文字列に対する利点は何ですか?

65
anonymous

XX:+ UseCompressedStringsCompact Stringsは異なるものです。

UseCompressedStringsは、ASCIIのみがbyte[]に変換できるストリングでしたが、これはデフォルトでオフでした。ただし、フラグ自体ではなく、組み込みです。

Java-9文字列がUTF-16エンコーディングでchar[]として内部的に保存されるまで。 Java-9以降では、byte[]として保存されます。どうして?

ISO_LATIN_1では、各文字を1バイト(8ビット)でエンコードできるのに対し、これまで使用されていたもの(16ビット、使用されない場合は各8ビット)であるためです。これはISO_LATIN_1に対してonlyで動作しますが、とにかく使用される文字列の大部分です。

したがって、これはスペース使用量に対して行われます。

以下は、物事をより明確にするための小さな例です。

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ビットはゼロです。 2番目の場合、ゼロ以外の値になります。つまり、最上位8から少なくとも1ビットが存在することを意味します。

つまり、文字列を文字の配列として内部に格納すると、実際には各文字の半分を無駄にする文字列リテラルが存在します。このため、実際には多くのスペースを浪費する複数のアプリケーションがあります。

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のみの場合、コーダーはゼロになるため、値の長さ(バイト配列)はcharsのサイズになります。 Latin1以外の場合は2で割ります。

24
Eugene

Compact Stringsは両方の長所を備えています。

OpenJDKドキュメントで提供される定義に見られるように:

新しいStringクラスは、文字列の内容に基づいて、ISO-8859-1/Latin-1(文字あたり1バイト)またはUTF-16(文字あたり2バイト)としてエンコードされた文字を格納します。エンコーディングフラグは、使用されているエンコーディングを示します。

@Eugeneで述べたように、ほとんどの文字列はLatin-1形式でエンコードされ、文字ごとに1バイトを必要とするため、現在のStringクラスの実装で提供される2バイトスペース全体を必要としません。

新しいStringクラスの実装は、UTF-16 char arrayからa byte arrayに移行しますプラスエンコードフラグフィールド。追加のencoding fieldは、文字がUTF-16形式またはLatin-1形式を使用して保存されているかどうかを示します。

これにより、必要に応じてUTF-16形式で文字列を保存することもできます。また、これはJava 6の圧縮文字列とJava 9の圧縮文字列の違いの主なポイントになります- byte [] arrayのみがストレージに使用され、pure ASCIIとして表されました。

7
Dhaval Simaria

圧縮された文字列(-XX:+ UseCompressedStrings)

これは、Java 6Update 21で導入されたオプション機能でした-バイトでUS-ASCII文字列のみをエンコードすることでパフォーマンスを向上させる SPECjbb 文字ごと。

この機能は、-XXフラグ(-XX:+UseCompressedStrings)によって有効にできます。有効にすると、String.valueはオブジェクト参照に変更され、7ビットのUS-ASCII文字のみを含む文字列の場合はbyte[]、またはchar[]を指すようになります。

後で、Java 7でメンテナンスが高く、テストが難しいため削除されました。

コンパクト文字列

これは、メモリ効率の良い文字列を構築するためにJava 9で導入された新しい機能です。

Java 9より前、文字列クラスは文字をchar配列に格納し、各文字に2バイトを使用していましたが、Java 9 byte[](文字ごとに1バイト)またはchar[](文字ごとに2バイト)、文字列の内容とエンコードフラグフィールドに基づきます。文字列文字がLatin-1型の場合文字がbyte[]タイプの場合はUTF-16が使用され、そうでない場合はchar[]が使用されますエンコードフラグは、使用されるエンコードを示します。

0
Mohit Tyagi