この質問の下部にあるコードは少し長いですが、基本的にいくつかのオブジェクトを作成し、メモリ内のサイズを決定します。次の JVM パラメーターを使用してコードを実行します (チャンク メモリの割り当てを回避し、正確なメモリ使用量を取得するための TLAB)。
-server -Xms2000m -Xmx2000m -verbose:gc -XX:-UseTLAB
64 ビット Hotspot JVM でコードを実行すると、次の出力が得られます。
Java HotSpot(TM) 64 ビット サーバー VM
オブジェクト: 16 バイト1 つの int を持つオブジェクト: 16 バイト
2 つの int を持つオブジェクト: 24 バイト
3 つの int を持つオブジェクト: 24 バイトlong が 1 つのオブジェクト: 24 バイト long
が 2 つのオブジェクト: 32 バイトlong
が 3 つのオブジェクト: 40 バイト1 つの参照を持つオブジェクト: 16 バイト
2 つの参照を持つオブジェクト: 24 バイト
3 つの参照を持つオブジェクト: 24 バイト
私は次のように結論付けています。
- オブジェクトは、16 バイトにアラインされた 12 バイトを使用します。
- int には 4 バイトが必要です (1 つの int を持つ 1 つのオブジェクトは 12 + 4 = 16 バイトですが、2 つの int がある場合: 12 + 8 = 20 が 24 バイトに整列されます)
- long は 8 バイトかかります (1 つの long を持つ 1 つのオブジェクトは 12 + 8 = 20 バイトで、24 バイトにアラインされます)
しかし、参照が s ほど多くのスペースを使用しない理由を理解するのに苦労していますlong
。
参照は 64 ビット JVM では 8 バイトであるため、測定方法に問題があるという結論は明らかです*。何が起こっているのか、それを修正するために何ができるのかを説明できますか?
*注:
- 測定中に GC は実行されません。
- Netbeans プロファイラーを使用すると、同様の結果が得られます。
public class TestMemoryReference {
private static final int SIZE = 100_000;
private static Runnable r;
private static Object o = new Object();
private static Object o1 = new Object();
private static Object o2 = new Object();
private static Object o3 = new Object();
public static class ObjectWith1Int { int i; }
public static class ObjectWith2Ints { int i, j; }
public static class ObjectWith3Ints { int i, j, k; }
public static class ObjectWith1Long { long i; }
public static class ObjectWith2Longs { long i, j; }
public static class ObjectWith3Longs { long i, j, k; }
public static class ObjectWith1Object { Object o = o1; }
public static class ObjectWith2Objects { Object o = o1; Object p = o2; }
public static class ObjectWith3Objects { Object o = o1; Object p = o2; Object q = o3; }
private static void test(Runnable r, String name, int numberOfObjects) {
long mem = Runtime.getRuntime().freeMemory();
r.run();
System.out.println(name + ":" + (mem - Runtime.getRuntime().freeMemory()) / numberOfObjects + " bytes ");
}
public static void main(String[] args) throws Exception {
System.out.println(System.getProperty("java.vm.name") + " ");
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new Object(); } };
test(r, "Object", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Int(); } };
test(r, "Object with 1 int", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Ints(); } };
test(r, "Object with 2 ints", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Ints(); } };
test(r, "Object with 3 ints", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Long(); } };
test(r, "Object with 1 long", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Longs(); } };
test(r, "Object with 2 longs", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Longs(); } };
test(r, "Object with 3 longs", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Object(); } };
test(r, "Object with 1 reference", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Objects(); } };
test(r, "Object with 2 references", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Objects(); } };
test(r, "Object with 3 references", SIZE);
}
}