Java Integer的緩存策略

Java5爲Integer的操做引入了一個新的特性,用來節省內存和提升性能。整型對象在內部實現中經過使用相同的對象引用實現了緩存和重用。
上面的規則默認適用於整數區間 -128 到 +127(這個整數區間能夠經過啓動應用的虛擬機參數修改:-XX:AutoBoxCacheMax)。這種Integer緩存策略僅在自動裝箱(autoboxing)的時候有用,使用構造器建立的Integer對象不能被緩存。Java 編譯器把原始類型自動轉換爲封裝類的過程稱爲自動裝箱(autoboxing),這至關於調用 valueOf 方法。java

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
}

首先看代碼:數組

public class TestInteger {
  public static void main(String[] args) {
    int i = 128;
    Integer i2 = 128;
    Integer i3 = new Integer(128);
    //Integer會自動拆箱爲int,因此爲true
    System.out.println(i == i2);
    System.out.println(i == i3);
    System.out.println("**************");
    Integer i5 = 127;//java在編譯的時候,被翻譯成-> Integer i5 = Integer.valueOf(127);
    Integer i6 = 127;
    System.out.println(i5 == i6);//true
    Integer i9 = 128;
    Integer i10 = 128;
    System.out.println(i9 == i10);//false
    Integer ii5 = new Integer(127);
    System.out.println(i5 == ii5); //false
    Integer i7 = new Integer(128);
    Integer i8 = new Integer(123);
    System.out.println(i7 == i8);  //false
  }
}

首先,7行和8行輸出結果都爲true,由於Integer和int比都會自動拆箱(jdk1.5以上)。
12行的結果爲true,而15行則爲false。java在編譯Integer i5 = 127的時候,被翻譯成-> Integer i5 = Integer.valueOf(127);因此關鍵就是看valueOf()函數了。只要看看valueOf()函數的源碼就會明白了。JDK源碼的 valueOf函數式這樣的:緩存

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
  }

看一下源碼你們都會明白,對於-128到127之間的數,會進行緩存,Integer i5 = 127時,會將127進行緩存,下次再寫Integer i6 = 127時,就會直接從緩存中取,就不會new了。因此12行的結果爲true,而15行爲false。
對於17行和20行,由於對象不同,因此爲false。
對於以上的狀況總結以下:函數

  • 不管如何,Integer與new Integer不會相等。不會經歷拆箱過程,i3的引用指向堆,而i4指向專門存放他的內存(常量池),他們的內存地址不同,因此爲false
  • 兩個都是非new出來的Integer,若是數在-128到127之間,則是true,不然爲false。java在編譯Integer i2 = 128的時候,被翻譯成-> Integer i2 = Integer.valueOf(128);而valueOf()函數會對-128到127之間的數進行緩存
  • 兩個都是new出來的,都爲false
  • int和Integer(不管new否)比,都爲true,由於會把Integer自動拆箱爲int再去比

AutoBoxCacheMax參數

// IntegerCache,Integer類的內部類,注意它的屬性都是定義爲static final
private static class IntegerCache {
    //緩存的下界,-128,不可變
    static final int low = -128;
    //緩存上界,暫爲null
    static final int high;
    //緩存的整型數組
    static final Integer cache[];

    static {
        // 緩存上界,能夠經過JVM參數來配置
        int h = 127;
        String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            //最大的數組值是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() {
    }
}

-XX:AutoBoxCacheMax這個參數是設置Integer緩存上限的參數,在VM初始化期間java.lang.Integer.IntegerCache.high屬性能夠被設置和保存在私有的系統屬性sun.misc.VM class中。理論上講,當系統須要頻繁使用Integer時,或者說堆內存中存在大量的Integer對象時,能夠考慮提升Integer緩存上限,避免JVM重複創造對象,提升內存的使用率,減小GC的頻率,從而提升系統的性能。
理論歸理論,這個參數可否提升系統系統關鍵仍是要看堆中Integer對象到底有多少、以及Integer的建立的方式。若是堆中的Integer對象不多,從新設置這個參數並不會提升系統的性能。即便堆中存在大量的Integer對象,也要看Integer對象時如何產生的。性能

  1. 大部分Integer對象經過Integer.valueOf()產生。說明代碼裏存在大量的拆箱與裝箱操做。這時候設置這個參數會系統性能有所提升。
  2. 大部分Integer對象經過反射,new產生。這時候Integer對象的產生大部分不會走valueOf()方法,因此設置這個參數也是無濟於事。

JDK中其餘相似的緩存

Integer的緩存上限能夠經過Java虛擬機參數修改,Byte、Short、Long、Character的緩存則無法修改。翻譯

Bytecode

private static class ByteCache {
    private ByteCache(){}
    static final Byte cache[] = new Byte[-(-128) + 127 + 1];
    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Byte((byte)(i - 128));
    }
}

public static Byte valueOf(byte b) {
    final int offset = 128;
    return ByteCache.cache[(int)b + offset];
}

Short對象

private static class ShortCache {
    private ShortCache(){}
    static final Short cache[] = new Short[-(-128) + 127 + 1];
    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Short((short)(i - 128));
    }
}

public static Short valueOf(short s) {
    final int offset = 128;
    int sAsInt = s;
    if (sAsInt >= -128 && sAsInt <= 127) { // must cache
        return ShortCache.cache[sAsInt + offset];
    }
    return new Short(s);
}

Long內存

private static class LongCache {
    private LongCache(){}
    static final Long cache[] = new Long[-(-128) + 127 + 1];
    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Long(i - 128);
    }
}

public static Long valueOf(long l) {
    final int offset = 128;
    if (l >= -128 && l <= 127) { // will cache
        return LongCache.cache[(int)l + offset];
    }
    return new Long(l);
}

Characterget

private static class CharacterCache {
    private CharacterCache(){}
    static final Character cache[] = new Character[127 + 1];
    static {
        for (int i = 0; i < cache.length; i++)
            cache[i] = new Character((char)i);
    }
}

public static Character valueOf(char c) {
    if (c <= 127) { // must cache
        return CharacterCache.cache[(int)c];
    }
    return new Character(c);
}

示例:

public class AllCacheDemo {
    /**
     * 演示JDK內部緩存
     */
    public static void main(String[] args) {
        Integer a = 28;
        Integer b = 28;
        println(a == b);

        Byte c = 25;
        Byte d = 25;
        println(c==d);

        Short p=12;
        Short q=12;
        println(p==q);

        Long x=127L;
        Long y=127L;
        println(x==y);

        Character m='M';
        Character n='M';
        println(m==n);
    }

    public static void println(Object o){
        System.out.println(o);
    }
}

做者:劉曉;花名:愚谷。
點擊 閱讀更多 查看更多詳情

相關文章
相關標籤/搜索