1

重複の可能性:
メモリ内のバイトのサイズ - Java

これはある記事で読みました。私はそのまま貼り付けています:

  • クラスは少なくとも 8 バイトを使用します。したがって、**new Object();**ヒープに 8 バイトを割り当てるとします。
  • 各データ メンバーは、8 バイトを使用する long および double を除いて、4 バイトを使用します。データ メンバが 1 バイトの場合でも、4 バイトを使用します。さらに、使用されるメモリ量は 8 バイト ブロックで増加します。したがって、1 バイトを含むクラスがある場合、クラス用に 8 バイト、データ用に 8 バイト、合計 16 バイトを使用します (うめき声!)。

Javaバイトが4バイトを割り当てる/取るのは本当ですか? 空のクラスは8バイトかかりますか? ここも紛らわしい。

4

3 に答える 3

5

Java 仕様はメモリの使用を義務付けていないため、これは使用する JVM 実装によって異なります。

確かに、すべての JVM 実装でオブジェクトごとのオーバーヘッドが発生します (たとえば、実行時の型チェックを実装するため)。JVM は、フィールドをメモリ アラインすることを選択する場合があります (一部のプラットフォームでは、これにより、フィールドへのアクセスが大幅に高速化されます)。

ただし、メモリの配置のためにパディングされた配列メンバーがあり、(少なくとも Windows の oracle vm では) boolean[] が要素ごとに 1 バイトかかることを確認できる場合、私は非常に驚くでしょう。

また、適切に大きなヒープをアドレス指定する場合、参照型のフィールドのサイズが 8 バイトになる可能性があることに注意してください。

結論: 本当に知りたい場合は、ターゲット JVM のメモリ消費量を測定してください。

編集:好奇心から、小さな(不正確な)ベンチマークを書きました:

class FourBytes {
    byte a,b,c,d;
}

public class Test {

    long usedBefore = used();

    long used() {
        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    }

    public void before() {
        System.gc();
        usedBefore = used();
    }

    public void after(String text) {
        long usedAfter = used();
        System.out.println(text + "\t" + new BigDecimal(usedAfter - usedBefore).movePointLeft(6) + " bytes");
        before();
    }

    {
        int max = 1000000;
        before();
        boolean[] bools = new boolean[max];
        after("boolean in array");

        char[] chars = new char[max];
        after("char in array   ");

        Object[] objects = new Object[max];
        after("reference type in array");

        for (int i = 0; i < max; i++) {
            objects[i] = new Object();
        }
        after("Object instance  ");

        Byte[] bytes = new Byte[max];
        before();
        for (int i = 0; i < max; i++) {
            bytes[i] = new Byte((byte) i);
        }
        after("Byte instance    ");


        Integer[] integers = new Integer[max];
        before();
        for (int i = 0; i < max; i++) {
            integers[i] = new Integer(i);
        }
        after("Integer instance");

        FourBytes[] fbs = new FourBytes[max];
        before();
        for (int i = 0; i < max; i++) {
            fbs[i] = new FourBytes();
        }
        after("FourBytes instance");

    }

    public static void main(String[] args) throws Exception {
        new Test();
    }
}

の上

java version "1.7.0_02"
Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
Java HotSpot(TM) Client VM (build 22.0-b10, mixed mode, sharing)

それは印刷します:

boolean in array    1.183624 bytes
char in array       2.091768 bytes
reference type in array 4.091768 bytes
Object instance     8.023664 bytes
Byte instance       16.133408 bytes
Integer instance    16.147312 bytes
FourBytes instance  16.142568 bytes
于 2012-11-09T17:34:37.137 に答える
3

クラスは少なくとも 8 バイトを使用します。したがって、new Object();と言うと ヒープに 8 バイトを割り当てます。

OpenJDK/HotSpot JVM では、32 ビット JVM で 8 バイト、64 ビット JVM で 16 バイトを使用します。

各データ メンバーは、8 バイトを使用する long および double を除いて、4 バイトを使用します。

最小サイズは 4 バイトではなく 1 バイトです。参照は通常、64 ビット JVM でも 4 バイトを使用します。

データ メンバが 1 バイトの場合でも、4 バイトを使用します。

それは新しい考えです。どうやってその結論に達したのかわかりません。

さらに、使用されるメモリ量は 8 バイト ブロックで増加します。

技術的には、8 バイト境界に揃えられています。

したがって、1 バイトを含むクラスがある場合、そのクラスには 8 バイトが必要になります。

32 ビットまたは 64 ビットの JVM では、ヘッダーに 8 バイトまたは 12 バイト、さらにバイトに 1 バイトを使用し、次の 8 バイト境界に切り上げられます。

データ用に 8 バイト、合計 16 バイトです (うめき声!)。

確かに、可能性のあるすべての Byte オブジェクトはキャッシュされ、自動ボックス化されますが、これを行う理由はありません。Byte を明示的または暗黙的に作成する必要はありません。

Byte b = new Byte((byte) 1); // bad idea.
Byte b = 1; // simpler and more efficient
byte b = 1; // the most efficient option.
于 2012-11-09T18:12:10.460 に答える
2

少なくとも HotSpot JVM については、これは誤りです。そこでは、クラスのプリミティブ バイト フィールドは 1 バイトを使用しますが、クラスのインスタンスのサイズが 8 バイトから始まることは事実であり、フィールドはそれぞれ 8 バイトを使用するチャンクにグループ化されます。たとえば、次のことができます。 8 バイト境界を越えてフィールドを分割しないでください。

たとえば、http: //www.codeinstructions.com/2008/12/java-objects-memory-structure.htmlを参照してください。

于 2012-11-09T17:26:41.083 に答える