プリミティブとBox
まずはじめにプリミティブとBox型の配列を作成してどれだけメモリを使用するのか見たいです。
private static final int NUM = 100_000;
public static void main(String[] args) {
long beforeUse, afterUse, div;
beforeUse = memoryUsed();
int[] primitive = new int[NUM];
afterUse = memoryUsed();
div = afterUse - beforeUse;
out.println(" -- int[] -- ");
out.println(div);
out.println((double)div / primitive.length);
beforeUse = memoryUsed();
Integer[] classes = new Integer[NUM];
afterUse = memoryUsed();
div = afterUse - beforeUse;
out.println(" -- Integer[] unset -- ");
out.println(div);
out.println((double)div / classes.length);
for (int i = 0;i < classes.length;i++) {
classes[i] = i;
}
afterUse = memoryUsed();
div = afterUse - beforeUse;
out.println(" -- Integer[] set -- ");
out.println(div);
out.println((double)div / classes.length);
}
実行結果
-- boolean[] --
100016
1.00016
-- Boolean[] unset --
400016
4.00016
-- Boolean[] set --
400016
4.00016
-- byte[] --
100016
1.00016
-- Byte[] unset --
400016
4.00016
-- Byte[] set --
448528
4.48528
-- short[] --
200016
2.00016
-- Short[] unset --
400016
4.00016
-- Short[] set --
1923440
19.2344
-- char[] --
200016
2.00016
-- Character[] unset --
400016
4.00016
-- Character[] set --
2402512
24.02512
-- int[] --
400016
4.00016
-- Integer[] unset --
400016
4.00016
-- Integer[] set --
2202512
22.02512
-- long[] --
1048576
10.48576
-- Long[] unset --
400016
4.00016
-- Long[] set --
3105872
31.05872
-- float[] --
400016
4.00016
-- Float[] unset --
400016
4.00016
-- Float[] set --
2706352
27.06352
-- double[] --
1048576
10.48576
-- Double[] unset --
400016
4.00016
-- Double[] set --
3651112
36.51112
1要素あたりのメモリ使用[バイト]
型 | プリミティブ | Box型(unset) | Box型(set) |
---|---|---|---|
boolean / Boolean | 1.00 | 4.00 | 4.00 |
byte / Byte | 1.00 | 4.00 | 4.48 |
short / Short | 2.00 | 4.00 | 19.23 |
char / Character | 2.00 | 4.00 | 24.03 |
int / Integer | 4.00 | 4.00 | 27.06 |
long / Long | 10.49 | 4.00 | 36.51 |
float / Float | 4.00 | 4.00 | 27.06 |
double / Double | 10.49 | 4.00 | 31.06 |
配列を作成すると決まって16バイト使用しています。
プリミティブでlongとdoubleが想定していたよりもメモリを使用していたのがよくわかりません。
Box型(set)でCharacter以降は20バイト以上使用するので多用は厳禁といったところでしょうか。
Stringクラス
Stringクラスのメモリ使用量を見てみます。
// set empty
for (int i = 0;i < NUM;i++) {
ary[i] = "";
}
// set new String
for (int i = 0;i < NUM;i++) {
ary[i] = new String();
}
// set 10digit
for (int i = 0;i < NUM;i++) {
ary[i] = new String("0123456789");
}
-- String[] unset --
400016
4.00016
-- String[] set empty --
400016
4.00016
-- String[] set new String --
3105872
31.05872
-- String[] set 10digit --
3105872
31.05872
全ての要素にnew String
すると約31バイト消費します。ですがnew String("0123456789")
でも31バイトなのが不思議です。
内部要素のprivate final byte[] value;
が常に同じ参照になるからでしょうか。
なので全ての要素が一意になるように直してみました。
for (int i = 0;i < NUM;i++) {
ary[i] = String.format("%010d", i);
}
System.gc();
-- String[] set 10digit --
4998968
49.98968
1要素あたり49バイトとなりました。
HashMap
HashMapに10万要素入れます。
Map<String, String> map = new HashMap<>();
for (int i = 0;i < NUM;i++) {
map.put(String.valueOf(i), "A" + i);
}
13632176
136.32176
1要素あたり136バイトと成りました。
実装を見てみないと根拠がわからないので読んでみる必要がありそうです。