Javaの要素のメモリ使用量を調べる

## プリミティブとBox

まずはじめにプリミティブとBox型の配列を作成してどれだけメモリを使用するのか見たいです。

```.java
  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
```

### １要素あたりのメモリ使用[バイト]

|型|プリミティブ | 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クラスのメモリ使用量を見てみます。

```.java
// 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;`が常に同じ参照になるからでしょうか。

なので全ての要素が一意になるように直してみました。

```.java
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万要素入れます。

```.java
Map<String, String> map = new HashMap<>();
for (int i = 0;i < NUM;i++) {
    map.put(String.valueOf(i), "A" + i);
}
```

```
13632176
136.32176
```
１要素あたり136バイトと成りました。
実装を見てみないと根拠がわからないので読んでみる必要がありそうです。

[ソースコード](https://github.com/horitaku1124/java_study/tree/master/src/main/java)