Warum Caching-Werte für ganzzahlige Klassen im Bereich von -128 bis 127?

81

In Bezug auf meine vorherige Frage, warum ergeben == Vergleiche mit Integer.valueOf (String) unterschiedliche Ergebnisse für 127 und 128? Wir wissen, dass Integer classes einen Cache gibt, in dem Werte zwischen -128und gespeichert werden 127.

Ich frage mich nur, warum zwischen -128 und 127 ?

In der Dokumentation zu Integer.valueOf () wurde angegeben, dass " häufig angeforderte Werte zwischengespeichert werden " . Aber werden Werte zwischen -128und 127häufig für real angefordert? Ich fand häufig angeforderte Werte sehr subjektiv.
Gibt es einen möglichen Grund dafür?

In der Dokumentation heißt es außerdem: " ..und kann andere Werte außerhalb dieses Bereichs zwischenspeichern. "
Wie kann dies erreicht werden?

DnR
quelle
7
Zu der Dokumentation: Oracle deckt nur ihre Ärsche ab, falls sie sich entscheiden, das Verhalten später zu ändern. Beispielsweise können sie entscheiden, dass Java 9 von -1024 bis 1023 zwischengespeichert wird. Die Meldung lautet: Verlassen Sie sich nicht auf den Cache, der eine bestimmte Ganzzahl enthält oder nicht enthält.
Dawood ibn Kareem
7
Ich gehe davon aus, dass Sie viel häufiger von 0 nach X als von 13476 nach Y schleifen. Sie müssen entschieden haben, dass auch negative Werte enthalten sein sollten, und -128 -> 127 ist für ein vorzeichenbehaftetes Byte sinnvoll.
Jeroen Vannevel
2
Wird das Looping nicht fast immer mit primitiven Ints durchgeführt - nicht mit Boxed Integers? Caching gilt nicht.
Bradvido
2
Der Cache ist eine reine Leistungssache. Solange dies kein Leistungsproblem für Sie darstellt, sollte es Ihnen egal sein, welcher Bereich zwischengespeichert wird. (Es wäre die Höhe der Torheit, eine Abhängigkeit vom Integer-Caching in Ihren Code zu integrieren.)
Hot Licks
3
@ JohnR es ist in der Java-Sprachspezifikation, siehe Assylias Antwort unten.
Zac Thompson

Antworten:

105

Ich frage mich nur, warum zwischen -128 und 127?

Ein größerer Bereich von Ganzzahlen kann zwischengespeichert werden, aber mindestens diejenigen zwischen -128 und 127 müssen zwischengespeichert werden, da dies in der Java-Sprachspezifikation (Schwerpunkt Mine) vorgeschrieben ist:

Wenn der Wert p, der eingerahmt wird, wahr, falsch, ein Byte oder ein Zeichen im Bereich von \ u0000 bis \ u007f oder eine int oder kurze Zahl zwischen -128 und 127 (einschließlich) ist , dann seien r1 und r2 die Ergebnisse von zwei beliebige Boxumwandlungen von p. Es ist immer so, dass r1 == r2.

Die Gründe für diese Anforderung werden im selben Absatz erläutert:

Idealerweise würde das Boxen eines gegebenen Grundwerts p immer eine identische Referenz ergeben . In der Praxis ist dies mit vorhandenen Implementierungstechniken möglicherweise nicht möglich. Die obigen Regeln sind ein pragmatischer Kompromiss. Die letzte Klausel oben verlangt, dass bestimmte gemeinsame Werte immer in nicht unterscheidbare Objekte gepackt werden. [...]

Dies stellt sicher, dass in den meisten Fällen das Verhalten das gewünschte ist, ohne dass eine übermäßige Leistungseinbuße entsteht, insbesondere bei kleinen Geräten . Weniger speicherbeschränkte Implementierungen können beispielsweise alle Zeichen- und Kurzwerte sowie int- und long-Werte im Bereich von -32 KB bis + 32 KB zwischenspeichern.


Wie kann ich andere Werte außerhalb dieses Bereichs zwischenspeichern?

Sie können die -XX:AutoBoxCacheMaxJVM-Option verwenden, die in der Liste der verfügbaren Hotspot-JVM-Optionen nicht wirklich dokumentiert ist . Es wird jedoch in den Kommentaren innerhalb der IntegerKlasse um Zeile 590 erwähnt :

Die Größe des Caches kann durch die -XX:AutoBoxCacheMax=<size>Option gesteuert werden .

Beachten Sie, dass dies implementierungsspezifisch ist und möglicherweise auf anderen JVMs verfügbar ist oder nicht.

Assylien
quelle
2
Dies ist die vollständige und beste Antwort - die Frage verwechselt den Bereich von -128 bis 127 mit den "häufig angeforderten Werten", obwohl sie tatsächlich unterschiedliche Gründe haben. -128 bis 127 werden für das Boxen zwischengespeichert. "häufig angeforderte Werte" werden für die Leistung zwischengespeichert.
Zac Thompson
@ZacThompson, danke für den Hinweis. Mein vorheriger Kommentar war nicht korrekt. Der Schlüsselbegriff aus der Spezifikation lautet "ein int ... zwischen -128 und 127 (einschließlich), dann seien r1 und r2 das Ergebnis von zwei beliebigen Boxumwandlungen von p. Es ist immer so, dass r1 == r2 ist." Wenn ich das richtig verstehe, schreibt die Spezifikation vor, dass Integer.valueOf (X) == Integer.valueOf (X) wobei -128 <= X <= 127.
John R
Dies ist die einzige Antwort auf den "Warum" -Teil der Frage, der etwas anderes als "Es ist die Standardeinstellung" bietet. Diese Antwort ist jedoch nicht vollständig, da sie nicht den "Wie" -Teil der Frage behandelt. Wenn Sie auf die Antworten anderer in XX: AutoBoxCacheMax verweisen und Informationen zum Steuern des Caching-Verhaltens in anderen Implementierungen der JVM hinzufügen (oder angeben, welche JVM-Implementierungen Optionen zum Steuern dieses Verhaltens haben), ist dies eine vollständige Antwort.
John R
"In der Praxis ist dies mit vorhandenen Implementierungstechniken möglicherweise nicht möglich." Ich kann diese Zeile nicht bekommen. Kannst du es bitte erklären?
Niiraj874u
2
@ niiraj874u Die aktuelle Implementierung verwendet einen Cache, der sich im Speicher befindet. Jede "kanonische" Ganzzahl wird in diesem Cache gespeichert. Das Zwischenspeichern aller Ganzzahlen würde also bedeuten, dass Sie möglicherweise bis zu 2 ^ 32 Ganzzahlen (= 15+ GB) im Speicher halten müssen, was selbst auf einem modernen Desktop-Computer nicht zumutbar ist.
Assylias
22

-128 bis 127 ist die Standardgröße. Aber javadoc sagt auch , dass die Größe der Integer - Cache kann durch die gesteuerte -XX:AutoBoxCacheMax=<size>Option. Beachten Sie, dass nur ein hoher Wert festgelegt wird. Der niedrige Wert ist immer -128. Diese Funktion wurde in 1.6 eingeführt.

Warum -128 bis 127 - dies ist ein Byte-Wertebereich und es ist natürlich, ihn für einen sehr kleinen Cache zu verwenden.

Evgeniy Dorofeev
quelle
Wie können wir das umsetzen -XX:AutoBoxCacheMax=<size>?
DnR
Führen Sie Java -XX: AutoBoxCacheMax = 256 ... aus und Sie werden sehen, dass Integer.valueOf (256) == Integer.valueOf (256)
Evgeniy Dorofeev
Durch das Laufen java -XX:AutoBoxCacheMax=256in der Konsole bekam ichError:could not create the Java Virtual Machine
DnR
versuchen Sie Java-Version es sollte 1.6 oder höher sein, meine 1.7 funktioniert OK
Evgeniy Dorofeev
2
Richtig, deshalb sagt Javadoc ... kann kontrolliert werden ... mein Java ist 64 Bit
Evgeniy Dorofeev
5

Der Grund für das Zwischenspeichern kleiner Ganzzahlen ist, dass viele Algorithmen kleine Ganzzahlen in ihren Berechnungen verwenden. Daher lohnt es sich, den Aufwand für die Objekterstellung für diese Werte zu vermeiden.

Die Frage wird dann, welche Ganzzahlen zwischengespeichert werden sollen. Im Allgemeinen nimmt die Häufigkeit, mit der konstante Werte verwendet werden, tendenziell ab, wenn der absolute Wert der Konstanten zunimmt - jeder verbringt viel Zeit mit den Werten 1 oder 2 oder 10, relativ wenige verwenden den Wert 109 sehr intensiv; Bei weniger Leistung hängt es davon ab, wie schnell eine Ganzzahl für 722 erhalten werden kann. Java hat 256 Slots zugewiesen, die sich über den Bereich eines vorzeichenbehafteten Bytewerts erstrecken. Diese Entscheidung wurde möglicherweise durch die Analyse der zu diesem Zeitpunkt existierenden Programme getroffen, ist aber ebenso wahrscheinlich eine rein willkürliche. Es ist eine angemessene Menge an Platz zum Investieren, es kann schnell zugegriffen werden (Maske, um herauszufinden, ob der Wert im Bereich des Caches liegt, dann eine schnelle Tabellensuche, um auf den Cache zuzugreifen), und es wird definitiv die häufigsten Fälle abdecken.

Mit anderen Worten, ich denke, die Antwort auf Ihre Frage lautet: "Es ist nicht so subjektiv wie Sie dachten, aber die genauen Grenzen sind größtenteils eine Faustregelentscheidung ... und experimentelle Beweise waren, dass es gut genug war. ""

keshlam
quelle
3

Der maximal hohe Ganzzahlwert, der zwischengespeichert werden kann, kann über die Systemeigenschaft ie java.lang.Integer.IntegerCache.high( -XX:AutoBoxCacheMax) konfiguriert werden . Der Cache wird mithilfe eines Arrays implementiert.

    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() {}
}
theexamtime
quelle
0

Wenn Sie auf eine Integer-Klasse stoßen und immer im Bereich von -128 bis 127 boxen, ist es immer besser, das Integer-Objekt wie folgt in den int-Wert zu konvertieren.

<Your Integer Object>.intValue()
Teja
quelle