2

Java オブジェクトのサイズについて長い間検索してきましたが、このような回答がたくさんあります。誰もが Java オブジェクトのオーバーヘッドのサイズと、実際のサイズを計算する方法を教えてくれます。しかし、彼らはどのようにしてそれを知っているのでしょうか? 公式のオラクル文書から証拠は見つかりませんでした。その結論の証拠は何ですか?それとも、データはいくつかの実験に基づくいくつかの推測から得られたものですか?

別物。オブジェクトを測定するための「近似」方法があることが公式文書に記載されています-計測方法ですが、「近似」の意味を誰かが説明できますか? 正確なとき、そうでないとき。証拠を残したほうがいい。

4

4 に答える 4

5

実際のサイズを計算する方法。しかし、彼らはどのようにしてそれを知っているのでしょうか?

経験から。

公式のオラクル文書から証拠は見つかりませんでした。

JVM次第です。OpenJDK ベースの JVM の場合、ヘッダーに参照が含まれているため、32 ビット JVM のヘッダー サイズは 64 ビット JVM とは異なります。他の JVM はまた異なる可能性があります。

それとも、データはいくつかの実験に基づくいくつかの推測から得られたものですか?

基本的に、はい。

「およそ」の意味を誰か説明してくれませんか?

オブジェクトのサイズを測定すると、さまざまなことがわかります

  • オブジェクトの大きさは?(深さが浅い)
  • どのくらいのメモリを使用しますか? (オブジェクトの割り当ては 8 バイトでアラインされます。つまり、常に 8 の倍数です)
  • オブジェクトと参照されるすべてのオブジェクトが使用する領域はどれくらいですか? (深い深さ)
  • 破棄された場合、どのくらいのスペースが解放される可能性がありますか? (共有されているオブジェクトの数と、解放されたメモリの 2 つのフラグメントの中間に表示されているか)
  • スタックで使用されているスペース、またはオフ ヒープ メモリで使用されているスペースをカウントしますか?

知っておくべきことによって多くの異なる答えが得られることを考えると、計算に使用するこれらすべてにほぼ近い 1 つの数値を使用すると便利です。


ランタイムを使用して問題が発生するのは、TLAB が大きなブロックにデータを割り当てたことです。これらの大きなブロックは、マルチスレッドの方法でさらに割り当てることができます。欠点は、正確なメモリ使用情報が得られないことです。

static long memTaken() {
    final Runtime rt = Runtime.getRuntime();
    return rt.totalMemory() - rt.freeMemory();
}

public static void main(String... args) {
    long used1 = memTaken();
    Float i = new Float(0);
    long used2 = memTaken();
    System.out.println("new Float(0) used "+(used2 - used1)+" bytes.");
}

オプションなしで実行

new Float(0) used 0 bytes.

TLAB をオフにすると、-XX:-UseTLAB

new Float(0) used 336 bytes.

クラス自体をロードする必要があったため、これは予想よりもはるかに高くなっています。最初に追加して最初に Float のインスタンスを 1 つ作成すると、

Float j = new Float(1);

あなたが得る

new Float(0) used 16 bytes
于 2012-09-03T11:33:09.737 に答える
2

実装に依存するため、答えは経験的なものにすぎないと思います。

Java 仮想マシンは、オブジェクトの特定の内部構造を強制しません。

于 2012-09-03T11:16:03.413 に答える
1

私にとって最良の方法は、最も現実的な方法です。

long memTaken() {
  final Runtime rt = Runtime.getRuntime();
  return rt.totalMemory() - rt.freeMemory();
}
  1. イニシャルを覚えておいてくださいmemTaken()
  2. 100 万個のオブジェクトの配列を作成します (この数をヒープに合わせて調整します)。
  3. memTaken()覚えているものから引きます。

プロセス中に一時的な割り当てが発生する可能性があるため、GC も実行する必要があります。によって提供される保証はありませんSystem.gc()が、このアプローチは常に私にとってはうまくいきました:

for (int i = 0; i < 3; i++) { System.gc(); Thread.sleep(50); }

これにより安定した結果が得られるように注意する必要があります。たとえば、いくつかの異なるオブジェクト数のメモリ負荷を計算し、結果を比較する方法があります。それらはすべて、それらが提供するメモリ/インスタンスの回答に一致する必要があります。

私は以前にこれをアドバイスしたことがあり、不十分な解決策のために非難され、適切なツールを使用するように勧められましjvisualvmた. この方法で間違った結果が得られたことはありません。

于 2012-09-03T11:32:44.127 に答える
0

Java オブジェクトには、シャロー サイズと保持サイズの 2 つの異なるサイズがあります。オブジェクトの浅いサイズは、そのすべてのフィールドのサイズの合計です: プリミティブ メンバーの場合は単純であり、すべての非プリミティブ メンバーの場合はポインターのサイズです (これは 32 ビット アーキテクチャと 64 ビット アーキテクチャの間で異なります)。インストルメンテーションを使用して、実行時にオブジェクトの浅いサイズを見つけることができます。ここに素敵なチュートリアルがあります

保持サイズは、オブジェクトがガベージされるときに解放されるヒープ領域によって定義されます。オブジェクトの保持サイズを見つけることは、主にオブジェクトが通常他のオブジェクトで構成されているため、簡単ではありません。例えば:

public class Clazz {

    public byte[] member;

    public static void main(String[] args) {
        byte[] bytes = new byte[128];
        Clazz a = new Clazz();
        Clazz b = new Clazz();
        a.member = bytes;
        b.member = bytes;
    }
}

aの保持サイズは?そしてb?プロファイラーを使用して保持サイズを計算します (ほとんどのプロファイラーはそのために静的ヒープ分析を使用しています)。

于 2012-09-03T11:52:31.870 に答える