ボクシングとキャッシュ
Integerのキャッシュ
int
がボクシングされると java.lang.Integer
になりますが、このとき Integer.valueOf(int)
が使われます。
このことは次のようなボクシングされるコードを書いてコンパイルしてからjavapすればよく分かります。
public class IntBoxingSample {
public Integer boxing(int i) {
return i;
}
}
javapしてみた結果は次の通り。
Compiled from "IntBoxingSample.java"
public class IntBoxingSample {
public IntBoxingSample();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.Integer boxing(int);
Code:
0: iload_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: areturn
}
で、この Integer.valueOf(int)
ですが、 -128
から 127
までの範囲はキャッシュされます。
このことは言語仕様の5.1.7やInteger.valueOf(int)のJavadocに書かれています。
でもって、OpenJDKのコードを見た感じ、java.lang.Integer.IntegerCache.high
というシステムプロパティでキャッシュする範囲を変更できそうです。
というわけで次のようなコードを書いてコンパイルして普通に実行すると false
と表示されますが、 -Djava.lang.Integer.IntegerCache.high=1000
という風にシステムプロパティを設定して実行すると true
と表示されます。
public class Sample {
public static void main(String[] args) {
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b);
}
}
実行結果は次の通り。
% java Sample
false
% java -Djava.lang.Integer.IntegerCache.high=1000 Sample
true
他のプリミティブも見てみた
Byte
、 Short
、 Long
は Integer
と同じく -128
から 127
までキャッシュされていました。 ただしキャッシュの範囲は変更できません。
- Byte.valueOf(byte)のコードとByteのキャッシュ構築コード
- Short.valueOf(short)のコードとShortのキャッシュ構築コード
- Long.valueOf(long)のコードとLongのキャッシュ構築コード
それから Character
は 0
から 127
までキャッシュされていました。
ASCII文字コードの NUL
から DEL
ですね。
Boolean
は定数 TRUE
と FALSE
のどちらかを返すようになっています。
最後に Float
と Double
ですが、どちらもキャッシュせず常にインスタンス化するようになっていました。
浮動小数点数なので -128.0
から 127.0
の間にも膨大な量のインスタンスを生成し得るので、まあ、そりゃキャッシュしないか、という感じ。
まとめ
以上のように普段は意識しないような部分でキャッシュしておりパフォーマンス向上を図っていたりしています。
こういったJDKの努力に感謝しつつ、今後も意識せずにコーディングしようと思います。
Discussion