Neden -128 ile 127 aralığında Tamsayı sınıfı önbelleğe alma değerleri?


81

Önceki sorumla ilgili olarak, neden == Integer.valueOf (String) ile karşılaştırmalar 127 ve 128 için farklı sonuçlar veriyor? , ve Integer classarasında değerleri depolayan bir önbelleğe sahip olduğunu biliyoruz .-128127

Merak ediyorum, neden -128 ile 127 arasında ?

Integer.valueOf () belgelerine de belirtti " sıkça değerlerini istenen önbelleklendiği " . Fakat arasındaki -128ve 127sıklıkla gerçek olan değerler isteniyor mu? Sıkça istenen değerlerin çok öznel olduğunu düşündüm .
Bunun arkasında herhangi bir olası sebep var mı?

Dokümantasyondan da şunlar belirtildi: " ..ve bu aralığın dışındaki diğer değerleri önbelleğe alabilir. "
Bu nasıl elde edilebilir?


7
Belgelere yeniden bakın: Oracle, davranışı daha sonra değiştirmeye karar vermeleri durumunda sadece izmaritlerini koruyor. Örneğin, Java 9'un -1024'ten 1023'e kadar önbelleğe alacağına karar verebilirler. Mesaj, belirli bir tamsayı içeren veya içermeyen önbelleğe güvenmeyin.
Dawood ibn Kareem

7
0'dan X'e 13476'dan Y'ye göre çok daha sık döngü yaptığınızı varsayıyorum. Negatif değerlerin de dahil edilmesi gerektiğine karar vermiş olmalılar ve -128 -> 127 işaretli bayt için mantıklıdır.
Jeroen Vannevel

2
Döngüleme neredeyse her zaman ilkel tamsayılarla yapılmaz mı - kutulu Tamsayılar değil mi? Önbelleğe alma geçerli değildir.
bradvido

2
Önbellek tamamen bir performans meselesidir. Sizin için bir performans sorunu yaratmadığı sürece, hangi aralığın önbelleğe alındığını umursamamanız gerekir. (Kodunuza Tamsayı önbelleğe alma bağımlılığı eklemek çılgınlığın doruk noktası olacaktır.)
Hot Licks

3
@JohnR Java Dil spesifikasyonundadır, aşağıdaki assylias yanıtına bakın.
Zac Thompson

Yanıtlar:


105

Merak ediyorum, neden -128 ile 127 arasında?

Daha geniş bir tam sayı aralığı önbelleğe alınabilir , ancak en azından -128 ile 127 arasındakiler önbelleğe alınmalıdır çünkü Java Dil Spesifikasyonu tarafından zorunlu kılınmıştır (vurgu benim):

Kutulu p değeri true, false, bir bayt veya \ u0000 ila \ u007f aralığında bir karakter veya -128 ile 127 (dahil) arasında bir int veya kısa sayı ise , r1 ve r2'nin sonuçları olsun p'nin herhangi iki boks dönüşümü. Her zaman r1 == r2 durumudur.

Bu gerekliliğin gerekçesi aynı paragrafta açıklanmıştır:

İdeal olarak, belirli bir ilkel değeri kutulamak p, her zaman aynı referans verir . Uygulamada, mevcut uygulama tekniklerini kullanarak bu mümkün olmayabilir. Yukarıdaki kurallar pragmatik bir uzlaşmadır. Yukarıdaki son cümle, belirli ortak değerlerin her zaman ayırt edilemeyen nesneler halinde kutuya alınmasını gerektirir. [...]

Bu, en yaygın durumlarda, özellikle küçük cihazlarda aşırı bir performans cezası olmaksızın davranışın istenen davranış olmasını sağlar . Daha az bellek sınırlı uygulamalar, örneğin, tüm karakter ve kısa değerleri ve ayrıca -32K ila + 32K aralığındaki int ve long değerleri önbelleğe alabilir.


Bu aralığın dışındaki diğer değerleri nasıl önbelleğe alabilirim?

Mevcut Hotspot JVM Seçenekleri-XX:AutoBoxCacheMax listesinde gerçekte belgelenmeyen JVM seçeneğini kullanabilirsiniz . Ancak sınıf içinde 590. satırdaki yorumlarda bahsediliyor :Integer

Önbelleğin boyutu -XX:AutoBoxCacheMax=<size>seçenekle kontrol edilebilir .

Bunun uygulamaya özgü olduğunu ve diğer JVM'lerde mevcut olabileceğini veya olmayabileceğini unutmayın.


2
Bu tam ve en iyi cevaptır - soru -128 ila 127 aralığını "sıkça istenen değerlerle" karıştırır, aslında farklı nedenlerden dolayıdırlar. -128 ila 127, boks için önbelleğe alınır. Performans için "sık istenen değerler" önbelleğe alınır.
Zac Thompson

@ZacThompson, bunu işaret ettiğiniz için teşekkürler. Önceki yorumum doğru değildi. Spesifikasyondaki anahtar kelime öbeği "-128 ile 127 (dahil) arasında bir int ..., o zaman r1 ve r2, p'nin herhangi iki kutulu dönüşümünün sonucu olsun. Her zaman r1 == r2 olur." Yani doğru anlarsam, belirtim Integer.valueOf (X) == Integer.valueOf (X), burada -128 <= X <= 127.
John R

Bu, sorunun "varsayılandır" dışında bir şey sunan "neden" kısmının tek cevabıdır. Ancak bu cevap, sorunun "nasıl" kısmına değinmediği için tam değildir. XX: AutoBoxCacheMax üzerinde başkalarının yanıtlarına başvurmak ve JVM'nin diğer uygulamalarında önbelleğe alma davranışının nasıl kontrol edileceğine dair bilgi eklemek (veya hangi JVM uygulamalarının bu davranışı kontrol etmek için seçeneklere sahip olduğunu belirtmek) bunu tam bir yanıt haline getirecektir.
John R.

"Uygulamada, mevcut uygulama tekniklerini kullanarak bu mümkün olmayabilir." Bu satırı alamıyorum. Lütfen açıklar mısınız?
niiraj874u

2
@ niiraj874u Geçerli uygulama, bellekte bulunan bir önbellek kullanır - her "kurallı" tam sayı bu önbellekte tutulur. Bu nedenle, tüm tam sayıları önbelleğe almak, bellekte 2 ^ 32'ye kadar tamsayı (= 15+ GB) tutmanız gerekebileceği anlamına gelir; bu, modern bir masaüstü bilgisayarda bile mantıksız bir durumdur.
assylias

22

Varsayılan boyut -128 ila 127'dir. Ancak javadoc, Tamsayı önbelleğinin boyutunun seçenek tarafından kontrol edilebileceğini de söylüyor -XX:AutoBoxCacheMax=<size>. Yalnızca yüksek değeri ayarladığını, düşük değerin her zaman -128 olduğunu unutmayın. Bu özellik 1.6'da tanıtıldı.

Neden -128 ila 127 - bu bayt değer aralığıdır ve çok küçük bir önbellek için kullanmak doğaldır.


nasıl uygulayabiliriz -XX:AutoBoxCacheMax=<size>?
DnR

java -XX çalıştırın -XX: AutoBoxCacheMax = 256 ... ve göreceksiniz ki Integer.valueOf (256) == Integer.valueOf (256)
Evgeniy Dorofeev

java -XX:AutoBoxCacheMax=256konsolda koşarak , aldımError:could not create the Java Virtual Machine
DnR

java sürümünü deneyin - 1.6 veya üstü olmalı, 1.7 çalışıyorum TAMAM
Evgeniy Dorofeev

2
Doğru, bu yüzden javadoc diyor ki .. kontrol edilebilir ... Java'm 64 bit
Evgeniy Dorofeev

5

Küçük tam sayıları önbelleğe almanın nedeni, eğer soruyorsanız, birçok algoritmanın hesaplamalarında küçük tamsayılar kullanmasıdır, bu nedenle bu değerler için nesne oluşturma ek yükünden kaçınmak faydalı olabilir.

Soru daha sonra önbelleğe alınacak Tamsayılar olur. Yine genel olarak konuşursak, sabit değerlerin kullanılma sıklığı sabitin mutlak değeri arttıkça düşme eğilimindedir - herkes 1 veya 2 veya 10 değerlerini kullanarak çok fazla zaman harcar, görece çok azı 109 değerini çok kullanır. yoğun bir şekilde; daha az performans 722 için bir Tamsayının ne kadar hızlı alınabileceğine bağlıdır. Java, işaretli bir bayt değeri aralığını kapsayan 256 yuva ayırmayı seçti. Bu karar, o sırada var olan programları analiz ederek bilgilendirilmiş olabilir, ancak aynı derecede tamamen keyfi bir karar olabilir. Yatırım yapmak için makul miktarda bir alandır, hızlıca erişilebilir (değerin önbellek aralığında olup olmadığını öğrenmek için maske, ardından önbelleğe erişmek için hızlı bir tablo araması) ve kesinlikle en yaygın durumları kapsayacaktır.

Başka bir deyişle, sorunuzun cevabının "düşündüğünüz kadar öznel değil, ancak kesin sınırlar büyük ölçüde pratik bir karar ... ve deneysel kanıtlar bunun yeterince iyi olduğuydu. "


3

Önbelleğe alınabilen maksimum yüksek tamsayı değeri, sistem özelliği yani java.lang.Integer.IntegerCache.high( -XX:AutoBoxCacheMax) aracılığıyla yapılandırılabilir . Önbellek, bir dizi kullanılarak gerçekleştirilir.

    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 sınıfıyla karşılaştığınızda ve her zaman -128 ila 127 aralığında kutulu olduğunuzda, Integer nesnesini aşağıdaki gibi int değerine dönüştürmek her zaman daha iyidir.

<Your Integer Object>.intValue()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.