-128から127の範囲の整数クラスキャッシュ値はなぜですか?


81

前の質問に関して、なぜ== Integer.valueOf(String)との比較で127と128で異なる結果が得られるのですか?、我々はそれを知ってInteger classいる値を格納するキャッシュを持っている間-128127

不思議に思うのですが、なぜ-128から127の間ですか?

Integer.valueOf()のドキュメントは、それがあると述べ、「頻繁に要求された値をキャッシュします。しかし、-128との間の値は127実際に頻繁に要求されますか?頻繁に要求される値は非常に主観的だと思いました。
これの背後にある考えられる理由はありますか?

ドキュメントからも次のように述べられています:..そしてこの範囲外の他の値をキャッシュする可能性があります。
これはどのように達成できますか?


7
ドキュメントについて:オラクルは、後で動作を変更することにした場合に備えて、お尻をカバーしているだけです。たとえば、Java 9が-1024から1023までキャッシュすることを決定する場合があります。メッセージは、特定の整数を含む、または含まないキャッシュに依存しないでください。
Dawood ibn Kareem 2014年

7
13476からYよりも0からXにループする頻度が高いと思います。負の値も含める必要があると判断したはずであり、-128-> 127は符号付きバイトに適しています。
Jeroen Vannevel 2014年

2
ループはほとんどの場合、プリミティブ整数で行われていませんか?ボックス化された整数ではありませんか?キャッシングは適用されません。
bradvido 2014年

2
キャッシュは純粋にパフォーマンス上の問題です。パフォーマンスの問題が発生しない限り、キャッシュされる範囲を気にする必要はありません。(整数キャッシングへの依存関係をコードに組み込むのは愚かなことです。)
Hot Licks 2014年

3
@JohnRはJava言語仕様に含まれています。以下のassyliasの回答を参照してください。
ザックトンプソン

回答:


105

不思議に思うのですが、なぜ-128から127の間なのですか?

より広い範囲の整数キャッシュできますが、Java言語仕様(強調鉱山)で義務付けられているため、少なくとも-128〜127の整数キャッシュする必要あります。

ボックス化されている値pがtrue、false、バイト、または\ u0000〜 \ u007fの範囲のchar、または-128〜127 (両端を含む)のintまたはshortの数値の場合、r1とr2を次の結果とします。 pの任意の2つのボクシング変換。r1 == r2の場合は常にそうです。

この要件の理論的根拠は、同じ段落で説明されています。

理想的には、与えられたプリミティブ値pをボックス化すると、常に同一の参照が生成されます。実際には、これは既存の実装手法を使用して実行できない場合があります。上記のルールは実用的な妥協案です。上記の最後の節では、特定の共通値を常に区別できないオブジェクトにボックス化する必要があります。[...]

これにより、特に小さなデバイスで過度のパフォーマンスの低下を課すことなく、ほとんどの場合、動作が望ましいものになります。メモリ制限の少ない実装では、たとえば、すべてのchar値とshort値、および-32Kから+ 32Kの範囲のint値とlong値をキャッシュできます。


この範囲外の他の値をキャッシュするにはどうすればよいですか?

使用可能なホットスポットJVMオプションの-XX:AutoBoxCacheMaxリストには実際には記載されていないJVMオプション使用できます。ただしIntegerクラス内の590行目あたりのコメントに記載されています

キャッシュのサイズは-XX:AutoBoxCacheMax=<size>オプションで制御できます。

これは実装固有であり、他のJVMで使用できる場合とできない場合があることに注意してください。


2
これは完全で最良の答えです。実際にはさまざまな理由で、-128から127の範囲を「頻繁に要求される値」と混同しています。-128から127はボクシング用にキャッシュされます。「頻繁に要求される値」は、パフォーマンスのためにキャッシュされます。
ザックトンプソン

@ZacThompson、これを指摘してくれてありがとう。私の以前のコメントは正しくありませんでした。仕様のキーフレーズは、「int ... -128〜127(両端を含む)の場合、r1とr2をpの任意の2つのボクシング変換の結果とします。r1== r2の場合は常に」です。したがって、私が正しく理解していれば、仕様ではInteger.valueOf(X)== Integer.valueOf(X)であることが義務付けられています。ここで、-128 <= X <= 127です。–
John R

これは、「これがデフォルト」以外の何かを提供する質問の「理由」の部分に対する唯一の答えです。ただし、この回答は、質問の「方法」の部分に対応していないため、完全ではありません。XX:AutoBoxCacheMaxで他のユーザーの応答を参照し、JVMの他の実装でキャッシュ動作を制御する方法に関する情報を追加する(またはこの動作を制御するオプションがあるJVM実装を示す)と、これは完全な答えになります。
ジョンR

「実際には、これは既存の実装手法では実現できない可能性があります。」この行を取得できません。説明してもらえますか?
niiraj874u 2014年

2
@ niiraj874u現在の実装では、メモリに常駐するキャッシュを使用しています。各「正規」整数はそのキャッシュに保持されています。したがって、すべての整数をキャッシュすると、メモリに最大2 ^ 32の整数(= 15+ GB)を保持する必要がある可能性があります。これは、最新のデスクトップコンピュータでも不合理です。
assylias 2014年

22

-128〜127がデフォルトのサイズです。しかし、javadocは、整数キャッシュのサイズはオプションによって制御できるとも述べてい-XX:AutoBoxCacheMax=<size>ます。高い値のみを設定し、低い値は常に-128であることに注意してください。この機能は1.6で導入されました。

-128〜127の理由については、これはバイト値の範囲であり、非常に小さいキャッシュに使用するのが自然です。


どうすれば実装でき-XX:AutoBoxCacheMax=<size>ますか?
dnR 2014年

java -XX:AutoBoxCacheMax = 256 ...を実行すると、Integer.valueOf(256)== Integer.valueOf(256)
Evgeniy Dorofeev 2014年

java -XX:AutoBoxCacheMax=256コンソールで実行すると、次のようになりますError:could not create the Java Virtual Machine
DnR 2014年


2
そうです、これがjavadocが..制御される可能性があると言っている理由です...私のJavaは64ビットです
Evgeniy Dorofeev 2014年

5

小さい整数をキャッシュする理由は、それがあなたが求めているものである場合、多くのアルゴリズムが計算に小さい整数を使用するため、これらの値のオブジェクト作成オーバーヘッドを回避することは価値がある傾向があるためです。

次に、どの整数をキャッシュするかが問題になります。繰り返しになりますが、一般的に言えば、定数の絶対値が増加するにつれて、定数値が使用される頻度は減少する傾向があります-誰もが値1、2、または10を使用することに多くの時間を費やし、値109を使用する人は比較的少数です集中的に; 722の整数を取得できる速度に応じて、パフォーマンスが低下します。Javaは、符号付きバイト値の範囲にまたがる256スロットを割り当てることを選択しました。この決定は、その時点で存在するプログラムを分析することによって通知された可能性がありますが、純粋に恣意的なものであった可能性もあります。投資するのに妥当な量のスペースであり、迅速にアクセスでき(値がキャッシュの範囲内にあるかどうかを確認するためのマスク、次にキャッシュにアクセスするためのクイックテーブルルックアップ)、最も一般的なケースを確実にカバーします。

言い換えれば、あなたの質問に対する答えは、「あなたが思ったほど主観的ではありませんが、正確な範囲は主に経験則による決定です...そして実験的な証拠はそれが十分に良かったということです。 「」


3

キャッシュできる最大の高整数値は、システムプロパティjava.lang.Integer.IntegerCache.high((-XX:AutoBoxCacheMax))を使用して構成できます。キャッシュは配列を使用して実装されます。

    private static class IntegerCache {
    static final int high;
    static final Integer cache[];

    static {
        final int low = -128;

        // high value may be configured by property
        int h = 127;
        if (integerCacheHighPropValue != null) {
            // Use Long.decode here to avoid invoking methods that
            // require Integer's autoboxing cache to be initialized
            int i = Long.decode(integerCacheHighPropValue).intValue();
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - -low);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

    private IntegerCache() {}
}

0

Integerクラスに遭遇し、常に-128〜127の範囲内でボックス化されている場合は、以下のようにIntegerオブジェクトをint値に変換することをお勧めします。

<Your Integer Object>.intValue()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.