6

この質問の下部にあるコードは少し長いですが、基本的にいくつかのオブジェクトを作成し、メモリ内のサイズを決定します。次の 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);
    }
}
4

2 に答える 2

6

参照は 64 ビット JVM では 8 バイトであるため

これは、潜在的に欠陥のある仮定です。

HotSpot は、"compressed oops"を使用して、JVM のいくつかの場所で参照に 32 ビット値を使用できます(強調鉱山)。

どのおっとが圧縮されていますか?

ILP32 モードの JVM では、または UseCompressedOops フラグが LP64 モードでオフになっている場合、すべての oops はネイティブ マシン ワード サイズです。

UseCompressedOops が true の場合、ヒープ内の次の oops が圧縮されます。

  • すべてのオブジェクトのクラス フィールド
  • すべての oop インスタンス フィールド
  • oop 配列 (objArray) のすべての要素

これがあなたの場合に起こっていることだと思います

を使用してテストします

-XX:-UseCompressedOops

また

-XX:+UseCompressedOops

私のマシンでは、デフォルトであなたと同じ結果が得られますが、次の-XX:-UseCompressedOopsように表示されます。

Object:16 bytes
Object with 1 int:24 bytes
Object with 2 ints:24 bytes
Object with 3 ints:32 bytes
Object with 1 long:24 bytes
Object with 2 longs:32 bytes
Object with 3 longs:40 bytes
Object with 1 reference:24 bytes
Object with 2 references:32 bytes
Object with 3 references:40 bytes

...これはおそらくあなたが期待していたものに近いでしょう:)

于 2013-02-20T13:40:00.270 に答える
0

Java オブジェクトのサイズは、クラスが定義されているときにわかります。

Java オブジェクトのメモリ使用量: 一般http://www.javamex.com/tutorials/memory/object_memory_usage.shtml

于 2013-02-20T13:46:32.190 に答える