Javaでは、オブジェクトのサイズを決定するための最良の方法は何ですか?


617

大量のデータ行を含むCSVファイルを読み取るアプリケーションがあります。データの種類に基づいて行数の概要をユーザーに提供しますが、データの行数が多すぎてOutOfMemoryErrorsが発生しないようにしたいと思います。各行はオブジェクトに変換されます。プログラムでそのオブジェクトのサイズを確認する簡単な方法はありますか?のプリミティブ型とオブジェクト参照の大きさを定義する参照はありVMますか?

現在、最大32,000行を読み取るというコードがありますが、32MBのメモリを使用するまで、できるだけ多くの行を読み取るというコードも必要です。多分それは別の質問ですが、私はまだ知りたいです。


私はmvn configsでエージェントを追加し、ここでその方法を説明しました:stackoverflow.com/a/36102269/711855
juanmf

回答:


461

java.lang.instrumentパッケージを使用できます

このクラスをコンパイルしてJARに入れます。

import java.lang.instrument.Instrumentation;

public class ObjectSizeFetcher {
    private static Instrumentation instrumentation;

    public static void premain(String args, Instrumentation inst) {
        instrumentation = inst;
    }

    public static long getObjectSize(Object o) {
        return instrumentation.getObjectSize(o);
    }
}

次のものをに追加しますMANIFEST.MF

Premain-Class: ObjectSizeFetcher

getObjectSizeを使用します。

public class C {
    private int x;
    private int y;

    public static void main(String [] args) {
        System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
    }
}

で呼び出す:

java -javaagent:ObjectSizeFetcherAgent.jar C

2
@Stefan素敵なヒント!あなたはの大きさがどうなるか、教えてくださいすることができbyte[0]byte[1]byte[5]int[0]int[1]int[2]あなたが説明した手法を使用していますか?結果に配列の長さとオーバーヘッドのアライメントのオーバーヘッドが含まれていると、それはすばらしいことです。
dma_k 2010年

8
私はこれを試し、奇妙で役に立たない結果を得ました。文字列は、サイズに関係なく常に32でした。これはおそらくポインタサイズだと思いましたが、私が作成した別の不変クラスの場合、24を取得しました。これはプリミティブでうまく機能しますが、charの大きさを通知するプログラムは実際には必要ありません。
Brel

6
@Brelこのソリューションは、ドキュメントで指定されている「指定されたオブジェクトによって消費されるストレージ量の概算」にすぎません。また、Javaの文字列プールのために、文字列のサイズを32バイト(ポインタのみ?)に設定することにしたと思います。これにより、文字列インスタンスが共有されている(プールに保存されている)か、クラスに対してローカルで一意です。
Andrei I

11
jarをエクスポートしない場合、ObjectSizeFetcherをどのように使用できますか?私は日食でテストJavaプロジェクトを持っています。
Yura Shinkarev 2013

3
@brel文字列が実際の長さに関係なく32バイトしかない理由は、文字列の可変長部分が独自のオブジェクトであるchar []に格納されているためです。オブジェクトの実際のサイズを取得するには、オブジェクト自体のサイズとオブジェクトが参照する各オブジェクトのサイズを加算する必要があります。
tombrown52

117

OpenJDKプロジェクトの一部として開発されたツールであるjolを使用する必要があります。

JOL(Java Object Layout)は、JVMのオブジェクトレイアウトスキームを分析するための小さなツールボックスです。これらのツールは、Unsafe、JVMTI、およびServiceability Agent(SA)を多用して、実際のオブジェクトのレイアウト、フットプリント、および参照をデコードしています。これにより、JOLは、ヒープダンプや仕様の仮定などに依存する他のツールよりもはるかに正確になります。

プリミティブ、参照、および配列要素のサイズを取得するには、を使用しますVMSupport.vmDetails()。64ビットWindowsで実行されているOracle JDK 1.8.0_40(以下のすべての例で使用)では、このメソッドは

Running 64-bit HotSpot VM.
Using compressed oop with 0-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

を使用して、オブジェクトインスタンスの浅いサイズを取得できますClassLayout.parseClass(Foo.class).toPrintable()(オプションでインスタンスをに渡すtoPrintable)。これは、そのクラスの単一のインスタンスによって消費されるスペースのみです。そのクラスによって参照される他のオブジェクトは含まれません。これはないオブジェクトヘッダ、フィールド整列およびパディングのためのVMオーバーヘッドを含みます。の場合java.util.regex.Pattern

java.util.regex.Pattern object internals:
 OFFSET  SIZE        TYPE DESCRIPTION                    VALUE
      0     4             (object header)                01 00 00 00 (0000 0001 0000 0000 0000 0000 0000 0000)
      4     4             (object header)                00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000)
      8     4             (object header)                cb cf 00 20 (1100 1011 1100 1111 0000 0000 0010 0000)
     12     4         int Pattern.flags                  0
     16     4         int Pattern.capturingGroupCount    1
     20     4         int Pattern.localCount             0
     24     4         int Pattern.cursor                 48
     28     4         int Pattern.patternLength          0
     32     1     boolean Pattern.compiled               true
     33     1     boolean Pattern.hasSupplementary       false
     34     2             (alignment/padding gap)        N/A
     36     4      String Pattern.pattern                (object)
     40     4      String Pattern.normalizedPattern      (object)
     44     4        Node Pattern.root                   (object)
     48     4        Node Pattern.matchRoot              (object)
     52     4       int[] Pattern.buffer                 null
     56     4         Map Pattern.namedGroups            null
     60     4 GroupHead[] Pattern.groupNodes             null
     64     4       int[] Pattern.temp                   null
     68     4             (loss due to the next object alignment)
Instance size: 72 bytes (reported by Instrumentation API)
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total

を使用して、オブジェクトインスタンスの詳細なサイズの概要ビューを取得できますGraphLayout.parseInstance(obj).toFootprint()。もちろん、フットプリント内の一部のオブジェクトは共有されている可能性があるため(他のオブジェクトからも参照されます)、そのオブジェクトがガベージコレクションされたときに再利用される可能性のあるスペースの過大評価です。Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$")この回答から取られた)の結果について、jolは1840バイトの合計フットプリントを報告します。そのうち72のみがパターンインスタンス自体です。

java.util.regex.Pattern instance footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1       112       112   [C
         3       272       816   [Z
         1        24        24   java.lang.String
         1        72        72   java.util.regex.Pattern
         9        24       216   java.util.regex.Pattern$1
        13        24       312   java.util.regex.Pattern$5
         1        16        16   java.util.regex.Pattern$Begin
         3        24        72   java.util.regex.Pattern$BitClass
         3        32        96   java.util.regex.Pattern$Curly
         1        24        24   java.util.regex.Pattern$Dollar
         1        16        16   java.util.regex.Pattern$LastNode
         1        16        16   java.util.regex.Pattern$Node
         2        24        48   java.util.regex.Pattern$Single
        40                1840   (total)

代わりにを使用する場合GraphLayout.parseInstance(obj).toPrintable()、jolは、参照される各オブジェクトへのフィールド逆参照のアドレス、サイズ、タイプ、値、およびパスを通知しますが、これは通常、あまりにも詳細すぎて役に立ちません。進行中のパターンの例では、次のようになります。(アドレスは実行間で変更される可能性があります。)

java.util.regex.Pattern object externals:
          ADDRESS       SIZE TYPE                             PATH                           VALUE
         d5e5f290         16 java.util.regex.Pattern$Node     .root.next.atom.next           (object)
         d5e5f2a0        120 (something else)                 (somewhere else)               (something else)
         d5e5f318         16 java.util.regex.Pattern$LastNode .root.next.next.next.next.next.next.next (object)
         d5e5f328      21664 (something else)                 (somewhere else)               (something else)
         d5e647c8         24 java.lang.String                 .pattern                       (object)
         d5e647e0        112 [C                               .pattern.value                 [^, [, a, -, z, A, -, Z, 0, -, 9, _, ., +, -, ], +, @, [, a, -, z, A, -, Z, 0, -, 9, -, ], +, \, ., [, a, -, z, A, -, Z, 0, -, 9, -, ., ], +, $]
         d5e64850        448 (something else)                 (somewhere else)               (something else)
         d5e64a10         72 java.util.regex.Pattern                                         (object)
         d5e64a58        416 (something else)                 (somewhere else)               (something else)
         d5e64bf8         16 java.util.regex.Pattern$Begin    .root                          (object)
         d5e64c08         24 java.util.regex.Pattern$BitClass .root.next.atom.val$rhs        (object)
         d5e64c20        272 [Z                               .root.next.atom.val$rhs.bits   [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e64d30         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d48         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d60         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d78         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d90         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64da8         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64dc0         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs (object)
         d5e64dd8         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs        (object)
         d5e64df0         24 java.util.regex.Pattern$5        .root.next.atom                (object)
         d5e64e08         32 java.util.regex.Pattern$Curly    .root.next                     (object)
         d5e64e28         24 java.util.regex.Pattern$Single   .root.next.next                (object)
         d5e64e40         24 java.util.regex.Pattern$BitClass .root.next.next.next.atom.val$rhs (object)
         d5e64e58        272 [Z                               .root.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e64f68         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64f80         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e64f98         24 java.util.regex.Pattern$5        .root.next.next.next.atom.val$lhs.val$lhs (object)
         d5e64fb0         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$rhs (object)
         d5e64fc8         24 java.util.regex.Pattern$5        .root.next.next.next.atom.val$lhs (object)
         d5e64fe0         24 java.util.regex.Pattern$5        .root.next.next.next.atom      (object)
         d5e64ff8         32 java.util.regex.Pattern$Curly    .root.next.next.next           (object)
         d5e65018         24 java.util.regex.Pattern$Single   .root.next.next.next.next      (object)
         d5e65030         24 java.util.regex.Pattern$BitClass .root.next.next.next.next.next.atom.val$rhs (object)
         d5e65048        272 [Z                               .root.next.next.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e65158         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e65170         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e65188         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e651a0         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e651b8         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs.val$lhs (object)
         d5e651d0         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs (object)
         d5e651e8         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom (object)
         d5e65200         32 java.util.regex.Pattern$Curly    .root.next.next.next.next.next (object)
         d5e65220        120 (something else)                 (somewhere else)               (something else)
         d5e65298         24 java.util.regex.Pattern$Dollar   .root.next.next.next.next.next.next (object)

「(something other)」エントリは、このオブジェクトグラフの一部ではない、ヒープ内の他のオブジェクトを示します

最高のjolドキュメントは、jolリポジトリにあるjolサンプルです。サンプルは、一般的なjol操作を示し、jolを使用してVMおよびガベージコレクタの内部を分析する方法を示します。


18
この回答にはもっと賛成票があるはずです。間違いなくチェックするのに非常に良いオプションです。編集:質問が'08に尋ねられたときに、これが今年追加されたことを確認しました。おそらく、OPが現時点で求めていることを実行するための最良かつ最も簡単なオプションです。
賃料

4
ツールの作成者は、Jolに関するブログ投稿を書きまし
Mike

2
オブジェクト「obj」のサイズを確認するには、org.openjdk.jol.info.GraphLayout.parseInstance(obj).totalSize();を使用します。
活気ある

vmDetails今ですVM.current().details()
Miha_x64

GraphLayout.parseInstance(instance).toFootprint()オブジェクトのサイズを理解する方が便利だと思ったので確認してください
Mugen

82

私は誤って、すでにjdkにあるJavaクラス「jdk.nashorn.internal.ir.debug.ObjectSizeCalculator」を見つけました。これは使いやすく、オブジェクトのサイズを決定するのに非常に役立つようです。

System.out.println(ObjectSizeCalculator.getObjectSize(new gnu.trove.map.hash.TObjectIntHashMap<String>(12000, 0.6f, -1)));
System.out.println(ObjectSizeCalculator.getObjectSize(new HashMap<String, Integer>(100000)));
System.out.println(ObjectSizeCalculator.getObjectSize(3));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[]{1, 2, 3, 4, 5, 6, 7 }));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[100]));

結果:

164192
48
16
48
416

3
ここでも同じですが、私は上記で提案された他のソリューションを試していて、ObjectSizeCalculatorに出会いました。Nashornプロジェクトの一環としてJDK 8で最近導入されて以来、以前は誰も言及していなかったと思います。ただし、このクラスに関する公式ドキュメントはWeb上で見つかりませんでした。
Henrique Gontijo 2016年

文字列の長さを考慮していないようです。スタックのサイズとほぼ同じですか?
jontejj

1
私はハッシュマップを持っていますが、com.carrotsearch.RamUsageEstimatorはObjectSizeCalculatorの約半分を返します。どちらが本当ですか?-どちらがより安心ですか?
badera

9
ObjectSizeCalculatorHotSpot VMでのみサポートされていることに注意してください
kellanburket 2018

74

数年前のJavaworldには、複合および潜在的にネストされたJavaオブジェクトのサイズの決定に関する記事があり基本的にJavaでのsizeof()実装の作成について説明しています。このアプローチは基本的に、プリミティブと典型的なJavaオブジェクトのサイズを実験的に識別し、その知識をオブジェクトグラフを再帰的にウォークして合計サイズを計算するメソッドにその知識を適用する他の作業に基づいています。

単にクラスの舞台裏で起こっていることのために、それは常にネイティブC実装よりも多少正確ではありませんが、それは良い指標であるべきです。

あるいは、適切にsizeofと呼ばれるSourceForgeプロジェクトで、sizeof()実装を備えたJava5ライブラリーを提供します。

PSシリアル化アプローチを使用しないでください。シリアル化されたオブジェクトのサイズと、ライブ時に消費するメモリの量との間に相関関係はありません。


6
sizeofユーティリティがおそらく最も速い方法です。それは基本的にステファンが言ったことですが、すでに使用できるように瓶に詰められています。
アレクサンドルLテルス

62

まず、「オブジェクトのサイズ」は、Javaで明確に定義された概念ではありません。オブジェクト自体、そのメンバー、オブジェクト、およびオブジェクトが参照するすべてのオブジェクト(参照グラフ)のみを意味する場合があります。メモリ内のサイズまたはディスク上のサイズを意味する可能性があります。そして、JVMは文字列のようなものを最適化することができます。

したがって、唯一の正しい方法は、適切なプロファイラー(私はYourKitを使用)を使用してJVMに問い合わせることですが、これはおそらく望んでいることではありません。

ただし、上記の説明から、各行は自己完結型であり、大きな依存関係ツリーがないように思われるため、シリアル化メソッドは、ほとんどのJVMでおそらく適切な近似になります。これを行う最も簡単な方法は次のとおりです。

 Serializable ser;
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 ObjectOutputStream oos = new ObjectOutputStream(baos);
 oos.writeObject(ser);
 oos.close();
 return baos.size();

共通の参照を持つオブジェクトがある場合、これ正しい結果を与え、シリアル化のサイズは常にメモリ内のサイズと一致するとは限りませんが、これは適切な概算です。ByteArrayOutputStreamサイズを適切な値に初期化すると、コードは少し効率的になります。


2
私はこのアプローチが好きです。オブジェクトサイズの点でどれだけ離れていますか。
ベルリンブラウン

1
非常にシンプルで効果的です。他の方法はあまりにも面倒です(特にEclipse RCPの内部)。ありがとう。
marcolopes 2012

19
シリアル化は一時的な変数を追跡しません。デフォルトのシリアル化メソッドは文字列をUTF-8で書き込むため、ANSI文字は1バイトしか使用しません。多くの文字列がある場合、サイズが大きくなりすぎて役に立たなくなります。
TMN、2012

1
これは正確なサイズを提供しない場合がありますが、私のニーズでは、2つのオブジェクトの比較だけが必要で、SizeOfはWebアプリから初期化されません。ありがとう!
アイザック

1
YourKitの良い推薦。他の代替案は、VirtualVMjvmmonitorです
angelcervera

38

JVMで使用されているメモリの量と空き容量を知りたい場合は、次のようにしてみてください。

// Get current size of heap in bytes
long heapSize = Runtime.getRuntime().totalMemory();

// Get maximum size of heap in bytes. The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();

// Get amount of free memory within the heap in bytes. This size will increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();

編集:質問の作成者が「32MBのメモリを使用するまでできるだけ多くの行を読み取る」ことを処理するロジックが必要だと質問者が述べたので、これは役立つかもしれないと思いました。


24
ガベージコレクションがいつ発生するか、一度にヒープに割り当てられるメモリの量がわからないため、これは適切な解決策ではありません。
Nick Fortescue、

5
これは本当です。これでこの投稿の主な質問に対処するつもりはありませんが、最大ヒープサイズに少し近づいたときにプログラムで知るのに役立つかもしれません。
マットb

1
このソリューションの他の問題は、マルチスレッド環境(Webサーバーなど)にいる場合です。他のスレッドが実行中でメモリを消費していた可能性があります。この近似により、すべての仮想マシンで使用済みメモリが計算されます。
angelcervera 2013

1
もう1つの欠点は、freeMemoryが近似を返すことです。javax.crypto.Cipherオブジェクトを作成してみてください。(Cipherのサイズを推定するための)freeMemoryの2つの呼び出しの違いは一定ではありません!
Eugen

1
ガベージコレクションを強制できるので、このアプローチでいくつかのことができると思います。
matanster 2015

24

私がTwitterで働いていたときに、深いオブジェクトサイズを計算するためのユーティリティを書きました。さまざまなメモリモデル(32ビット、圧縮oops、64ビット)、パディング、サブクラスのパディングが考慮され、循環データ構造と配列で正しく機能します。この1つの.javaファイルをコンパイルするだけです。外部依存関係はありません:

https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java


1
シア!プレゼンテーションについても大声で伝えたいと思います。スライド15〜20は、さまざまなデータ構造決定のコストを直感的に理解するのに役立ちます。それを投稿してくれてありがとう!
Luke Usherwood、2015年

16
「外部依存関係はありません」-グアバはいつ外部依存関係にならないのですか?
l4mpi


Guaveは外部依存関係です。
Mert Serimer 2017

18

他の回答の多くは、浅いサイズを提供します。たとえば、キーや値のいずれもないHashMapのサイズです。

jammプロジェクトは上記のjava.lang.instrumentationパッケージを使用しますが、ツリーをたどるので、メモリを大量に使用できます。

new MemoryMeter().measureDeep(myHashMap);

https://github.com/jbellis/jamm

MemoryMeterを使用するには、「-javaagent:/jamm.jar」でJVMを起動します


11

反射を使用してオブジェクトを歩く必要があります。あなたがするように注意してください:

  • オブジェクトを割り当てるだけでは、JVMでオーバーヘッドが発生します。量はJVMによって異なるため、この値をパラメーターにする場合があります。少なくとも定数(8バイト?)にして、割り当てられたものすべてに適用します。
  • 理由だけでbyte、理論的には1つのバイトは、それがメモリ内に1つだけとるという意味ではありません。
  • オブジェクト参照にループがあるので、無限ループを排除するために、コンパレータとしてオブジェクトHashMap等値を使用してa などを維持する必要があります。

@jodonnell:私はソリューションの単純さが好きですが、多くのオブジェクトはシリアライズ可能ではないため(これにより例外がスローされます)、フィールドが一時的で、オブジェクトが標準メソッドをオーバーライドできます。


さまざまなプリミティブのサイズがJava仕様で定義されていませんか?(§2.4.1)
エリクソン2008

4
問題は、「どれだけのメモリを占有する」という意味ではありません。それらがどのように動作するかという意味でのみ。例えば、文字をバイト、ショートパンツは、彼らがなど。丸めで動作していても、Javaスタック上の全体の言葉を取る
ジェイソン・コーエン

1
これは、ハインツがニュースレター#78:javaspecialists.eu/archive/Issue078.htmlで示したように、サイズの測定に似ています。使った。彼のアプローチは機能します。
Peter Kofler、2009年

8

ツールを使用して測定するか、手動で推定する必要があります。使用するJVMによって異なります。

オブジェクトごとにいくつかの固定オーバーヘッドがあります。これはJVM固有ですが、通常は40バイトと推定しています。次に、クラスのメンバーを確認する必要があります。オブジェクト参照は、32ビット(64ビット)JVMでは4(8)バイトです。プリミティブタイプは次のとおりです。

  • ブールとバイト:1バイト
  • charおよびshort:2バイト
  • intおよびfloat:4バイト
  • longおよびdouble:8バイト

配列は同じ規則に従います。つまり、オブジェクト参照であり、オブジェクトで4(または8)バイトを使用し、その長さにその要素のサイズを掛けたものです。

Runtime.freeMemory()ガベージコレクターへの非同期呼び出しなどのため、を呼び出してプログラムで実行しようとすると、あまり正確にはなりません。-Xrunhprofまたは他のツールでヒープをプロファイリングすると、最も正確な結果が得られます。


@erickson私はこのスレッドを見ているsizeof(boolean)== 1について確信がありません(stackoverflow.com/questions/1907318/…)。これについてコメントしていただけますか?
dma_k 2010年

2
@ dma_k、Javaには実際には真のブール値はありません。ブール値のサイズは、配列の外では4バイト、内では1バイトですboolean[]。実際には、double / long型以外のすべてのプリミティブは4バイトです。後者は8です(答えが誤って4でもあるとしています)
bestss

@bestsss:より正確には、最小のメモリ割り当ては、プラットフォームとJVMの実装によって異なります。また、ヒープ上のオブジェクトは位置合わせされるため、すべてのサイズを合計した後、切り上げる必要があります。
dma_k

6

このjava.lang.instrument.Instrumentationクラスは、Javaオブジェクトのサイズを取得するための優れた方法を提供しpremainますが、Javaエージェントでを定義してプログラムを実行する必要があります。エージェントが不要で、アプリケーションにダミーのJarエージェントを提供する必要がある場合、これは非常に退屈です。

だから私はUnsafeからのクラスを使用して代替ソリューションを得ましたsun.misc。したがって、プロセッサアーキテクチャに応じたオブジェクトヒープの配置と最大フィールドオフセットの計算を考慮して、Javaオブジェクトのサイズを測定できます。以下の例でUtilUnsafeは、sun.misc.Unsafeオブジェクトへの参照を取得するために補助クラスを使用しています。

private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
private static final int BYTE = 8;
private static final int WORD = NR_BITS/BYTE;
private static final int MIN_SIZE = 16; 

public static int sizeOf(Class src){
    //
    // Get the instance fields of src class
    // 
    List<Field> instanceFields = new LinkedList<Field>();
    do{
        if(src == Object.class) return MIN_SIZE;
        for (Field f : src.getDeclaredFields()) {
            if((f.getModifiers() & Modifier.STATIC) == 0){
                instanceFields.add(f);
            }
        }
        src = src.getSuperclass();
    }while(instanceFields.isEmpty());
    //
    // Get the field with the maximum offset
    //  
    long maxOffset = 0;
    for (Field f : instanceFields) {
        long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f);
        if(offset > maxOffset) maxOffset = offset; 
    }
    return  (((int)maxOffset/WORD) + 1)*WORD; 
}
class UtilUnsafe {
    public static final sun.misc.Unsafe UNSAFE;

    static {
        Object theUnsafe = null;
        Exception exception = null;
        try {
            Class<?> uc = Class.forName("sun.misc.Unsafe");
            Field f = uc.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            theUnsafe = f.get(uc);
        } catch (Exception e) { exception = e; }
        UNSAFE = (sun.misc.Unsafe) theUnsafe;
        if (UNSAFE == null) throw new Error("Could not obtain access to sun.misc.Unsafe", exception);
    }
    private UtilUnsafe() { }
}

興味深いアプローチですが、これはオブジェクトとそのフィールドのストレージが断片化されていないと想定していますか?
nicoulaj 2012年

はい、そのような断片化を行うJVM実装は知りません。
ミゲルガンボア

分からない。断片化はオプションではありません:)オブジェクトAとBのフィールドとして格納されているオブジェクトCの例を見てみましょう。AまたはBのいずれかで全体をシフトしませんか?
nicoulaj 2012年

申し訳ありませんが、あなたの視点もよくわかりません。私の解釈によると、Javaオブジェクトは、C構造や.Netの値型で発生するような他のオブジェクト内に格納できません。つまり、「オブジェクトCはオブジェクトAおよびBのフィールドとして格納されます」と言う場合、オブジェクトAおよびBにはオブジェクトCへの参照(ポインタ)を格納するフィールドがあることを意味します。次に、AおよびBのサイズは次のようになります。そのフィールドのオフセットにオブジェクトCへの参照(ポインタ)のサイズを加えたもの。参照のサイズは1ワードのサイズです。
ミゲルガンボア

あ、そうか、浅いサイズについて話している。私の悪い。
nicoulaj 2012年

6

同様の質問で説明されているようにメモリメジャーツール(以前はGoogle Codeで、現在はGitHubにあります)もあり、シンプルで、商用に適したApache 2.0ライセンスの下で公開されています

また、メモリのバイト消費を測定する場合は、Javaインタープリターへのコマンドライン引数が必要ですが、それ以外の場合は、少なくとも私が使用したシナリオでは正常に機能するようです。


4

インストルメンテーションなどをいじる必要がなく、オブジェクトの正確なバイトサイズを知る必要がない場合は、次の方法を使用できます。

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

do your job here

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

このようにして、使用済みメモリを前後に読み取り、使用済みメモリを取得する直前にGCを呼び出すと、「ノイズ」がほぼ0になります。

より信頼性の高い結果を得るには、ジョブをn回実行し、使用済みメモリをnで除算して、1回の実行に必要なメモリ量を取得します。さらに、全体をより多く実行して平均を出すことができます。


5
System.gc()GCを実行することを通知するだけではありませんか?GCが呼び出されることは保証されていません。
Raildex

@すごくいい。GCが行間でメモリを実行したりメモリに影響を与えたりすることは決してないため、これは安全ではありません。したがって、2つのfreeMemoryメソッドの「間」GCは、考慮しないスペースを解放できるため、オブジェクトが小さく見える
Mert Serimer

@MertSerimerは「安全ではない」というのは私にとってまったく異なるレベルです。私が述べたように、多くてもこれはそれほど正確ではありません。また、(Raildexが述べたように)GCを駆動することはできませんが、この場合もサイクルに挿入することをお勧めします。これは、述べられているように、結果が非​​常に信頼性を必要としない場合に機能する、迅速かつダーティでおおよそのシステムです。
本当に素敵な

これには多くの問題がありますが、それはあなたに良い盗品を与えます。
markthegrea

3

以下は、リンクされたいくつかの例を使用して、32ビット、64ビット、64ビットを圧縮OOPで処理するために作成したユーティリティです。使用しsun.misc.Unsafeます。

Unsafe.addressSize()ネイティブポインターのサイズを取得しUnsafe.arrayIndexScale( Object[].class )、Java参照のサイズを取得するために使用します。

既知のクラスのフィールドオフセットを使用して、オブジェクトの基本サイズを計算します。

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.Stack;
import sun.misc.Unsafe;

/** Usage: 
 * MemoryUtil.sizeOf( object )
 * MemoryUtil.deepSizeOf( object )
 * MemoryUtil.ADDRESS_MODE
 */
public class MemoryUtil
{
    private MemoryUtil()
    {
    }

    public static enum AddressMode
    {
        /** Unknown address mode. Size calculations may be unreliable. */
        UNKNOWN,
        /** 32-bit address mode using 32-bit references. */
        MEM_32BIT,
        /** 64-bit address mode using 64-bit references. */
        MEM_64BIT,
        /** 64-bit address mode using 32-bit compressed references. */
        MEM_64BIT_COMPRESSED_OOPS
    }

    /** The detected runtime address mode. */
    public static final AddressMode ADDRESS_MODE;

    private static final Unsafe UNSAFE;

    private static final long ADDRESS_SIZE; // The size in bytes of a native pointer: 4 for 32 bit, 8 for 64 bit
    private static final long REFERENCE_SIZE; // The size of a Java reference: 4 for 32 bit, 4 for 64 bit compressed oops, 8 for 64 bit
    private static final long OBJECT_BASE_SIZE; // The minimum size of an Object: 8 for 32 bit, 12 for 64 bit compressed oops, 16 for 64 bit
    private static final long OBJECT_ALIGNMENT = 8;

    /** Use the offset of a known field to determine the minimum size of an object. */
    private static final Object HELPER_OBJECT = new Object() { byte b; };


    static
    {
        try
        {
            // Use reflection to get a reference to the 'Unsafe' object.
            Field f = Unsafe.class.getDeclaredField( "theUnsafe" );
            f.setAccessible( true );
            UNSAFE = (Unsafe) f.get( null );

            OBJECT_BASE_SIZE = UNSAFE.objectFieldOffset( HELPER_OBJECT.getClass().getDeclaredField( "b" ) );

            ADDRESS_SIZE = UNSAFE.addressSize();
            REFERENCE_SIZE = UNSAFE.arrayIndexScale( Object[].class );

            if( ADDRESS_SIZE == 4 )
            {
                ADDRESS_MODE = AddressMode.MEM_32BIT;
            }
            else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 8 )
            {
                ADDRESS_MODE = AddressMode.MEM_64BIT;
            }
            else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 4 )
            {
                ADDRESS_MODE = AddressMode.MEM_64BIT_COMPRESSED_OOPS;
            }
            else
            {
                ADDRESS_MODE = AddressMode.UNKNOWN;
            }
        }
        catch( Exception e )
        {
            throw new Error( e );
        }
    }


    /** Return the size of the object excluding any referenced objects. */
    public static long shallowSizeOf( final Object object )
    {
        Class<?> objectClass = object.getClass();
        if( objectClass.isArray() )
        {
            // Array size is base offset + length * element size
            long size = UNSAFE.arrayBaseOffset( objectClass )
                    + UNSAFE.arrayIndexScale( objectClass ) * Array.getLength( object );
            return padSize( size );
        }
        else
        {
            // Object size is the largest field offset padded out to 8 bytes
            long size = OBJECT_BASE_SIZE;
            do
            {
                for( Field field : objectClass.getDeclaredFields() )
                {
                    if( (field.getModifiers() & Modifier.STATIC) == 0 )
                    {
                        long offset = UNSAFE.objectFieldOffset( field );
                        if( offset >= size )
                        {
                            size = offset + 1; // Field size is between 1 and PAD_SIZE bytes. Padding will round up to padding size.
                        }
                    }
                }
                objectClass = objectClass.getSuperclass();
            }
            while( objectClass != null );

            return padSize( size );
        }
    }


    private static final long padSize( final long size )
    {
        return (size + (OBJECT_ALIGNMENT - 1)) & ~(OBJECT_ALIGNMENT - 1);
    }


    /** Return the size of the object including any referenced objects. */
    public static long deepSizeOf( final Object object )
    {
        IdentityHashMap<Object,Object> visited = new IdentityHashMap<Object,Object>();
        Stack<Object> stack = new Stack<Object>();
        if( object != null ) stack.push( object );

        long size = 0;
        while( !stack.isEmpty() )
        {
            size += internalSizeOf( stack.pop(), stack, visited );
        }
        return size;
    }


    private static long internalSizeOf( final Object object, final Stack<Object> stack, final IdentityHashMap<Object,Object> visited )
    {
        // Scan for object references and add to stack
        Class<?> c = object.getClass();
        if( c.isArray() && !c.getComponentType().isPrimitive() )
        {
            // Add unseen array elements to stack
            for( int i = Array.getLength( object ) - 1; i >= 0; i-- )
            {
                Object val = Array.get( object, i );
                if( val != null && visited.put( val, val ) == null )
                {
                    stack.add( val );
                }
            }
        }
        else
        {
            // Add unseen object references to the stack
            for( ; c != null; c = c.getSuperclass() )
            {
                for( Field field : c.getDeclaredFields() )
                {
                    if( (field.getModifiers() & Modifier.STATIC) == 0 
                            && !field.getType().isPrimitive() )
                    {
                        field.setAccessible( true );
                        try
                        {
                            Object val = field.get( object );
                            if( val != null && visited.put( val, val ) == null )
                            {
                                stack.add( val );
                            }
                        }
                        catch( IllegalArgumentException e )
                        {
                            throw new RuntimeException( e );
                        }
                        catch( IllegalAccessException e )
                        {
                            throw new RuntimeException( e );
                        }
                    }
                }
            }
        }

        return shallowSizeOf( object );
    }
}

このクラスを値でテストしましたか?私は試しましたが、私にとっては間違った値!!!
デボラ2014

1
単純なオブジェクトに対して私に与えた値はほぼ正しいですが、1mioオブジェクトを含むリストの場合は10倍ずれています。それでも、とても素晴らしい仕事です!
MichaelBöckling2014

面白い。Windows 7 x64およびLinux 2.6.16 / x86_64で、32ビット/ 64ビット/ oopアドレスモードをそれぞれ使用して、JDK7u67を使用してテストしました。Eclipse Memory Analyzer 1.3.xで分析したメモリダンプと比較しました。どのセットアップを使用していますか?私が試せる具体的な例はありますか?
dlaudams 2014

私ができる最善の選択。VMタイプ(HotSpot)とBacouse Spring BeanがInstrumentationわからないObjectSizeCalculatorため、tomcatを起動しないため、使用できませんJOL。これを使用して、シングルトンを無視するための2番目のパラメーターを追加し、コードをAbstractRefreshableApplicationContext.getBeanFactory().getSingletonMutex()リファクタリングinternalSizeOfしてクラスと列挙型を無視します
Perlos

結果を比較するには、ObjectSizeCalculatorを使用します(サーバー全体を1GBから10sで計算します)。JOLはMemErrorを引き起こし(6GBはわからない)、おそらく列挙型が原因で同じ結果が得られません。
ペルロス2018

3

次の要件を満たすオブジェクトサイズのランタイム計算を探していました。

  • インストルメンテーションを含める必要なく、実行時に使用できます。
  • UnsafeにアクセスせずにJava 9以降で動作します。
  • クラスのみに基づいています。文字列の長さ、配列の長さなどを考慮した深いsizeOfではありません。

以下は、元のJavaスペシャリストの記事(https://www.javaspecialists.eu/archive/Issue078.html)のコアコードと、この質問に対する別の回答のUnsafeバージョンのいくつかのビットに基づいています

私は誰かがそれが役に立つと思うことを望みます。

public class JavaSize {

private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
private static final int BYTE = 8;
private static final int WORD = NR_BITS / BYTE;
private static final int HEADER_SIZE = 8;

public static int sizeOf(Class<?> clazz) {
    int result = 0;

    while (clazz != null) {
        Field[] fields = clazz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            if (!Modifier.isStatic(fields[i].getModifiers())) {
                if (fields[i].getType().isPrimitive()) {
                    Class<?> primitiveClass = fields[i].getType();
                    if (primitiveClass == boolean.class || primitiveClass == byte.class) {
                        result += 1;
                    } else if (primitiveClass == short.class) {
                        result += 2;
                    } else if (primitiveClass == int.class || primitiveClass == float.class) {
                        result += 4;
                    } else if (primitiveClass == double.class || primitiveClass == long.class) {
                        result += 8;
                    }

                } else {
                    // assume compressed references.
                    result += 4;
                }
            }
        }

        clazz = clazz.getSuperclass();

        // round up to the nearest WORD length.
        if ((result % WORD) != 0) {
            result += WORD - (result % WORD);
        }
    }

    result += HEADER_SIZE;

    return result;
}

}


2

それがあなたが求めているものであるならば、メソッド呼び出しはありません。少し調べれば、自分で書けると思います。特定のインスタンスには、参照の数とプリミティブ値、およびインスタンスの簿記データから派生した固定サイズがあります。オブジェクトグラフを歩くだけです。行タイプの変化が少ないほど、簡単になります。

それが遅すぎる、またはそれが意味するよりも問題が多い場合は、常に古き良き行カウントの経験則があります。


2

オンザフライで推定するためのクイックテストを1回作成しました。

public class Test1 {

    // non-static nested
    class Nested { }

    // static nested
    static class StaticNested { }

    static long getFreeMemory () {
        // waits for free memory measurement to stabilize
        long init = Runtime.getRuntime().freeMemory(), init2;
        int count = 0;
        do {
            System.out.println("waiting..." + init);
            System.gc();
            try { Thread.sleep(250); } catch (Exception x) { }
            init2 = init;
            init = Runtime.getRuntime().freeMemory();
            if (init == init2) ++ count; else count = 0;
        } while (count < 5);
        System.out.println("ok..." + init);
        return init;
    }

    Test1 () throws InterruptedException {

        Object[] s = new Object[10000];
        Object[] n = new Object[10000];
        Object[] t = new Object[10000];

        long init = getFreeMemory();

        //for (int j = 0; j < 10000; ++ j)
        //    s[j] = new Separate();

        long afters = getFreeMemory();

        for (int j = 0; j < 10000; ++ j)
            n[j] = new Nested();

        long aftersn = getFreeMemory();

        for (int j = 0; j < 10000; ++ j)
            t[j] = new StaticNested();

        long aftersnt = getFreeMemory();

        System.out.println("separate:      " + -(afters - init) + " each=" + -(afters - init) / 10000);
        System.out.println("nested:        " + -(aftersn - afters) + " each=" + -(aftersn - afters) / 10000);
        System.out.println("static nested: " + -(aftersnt - aftersn) + " each=" + -(aftersnt - aftersn) / 10000);

    }

    public static void main (String[] args) throws InterruptedException {
        new Test1();
    }

}

一般的な概念は、オブジェクトを割り当て、空きヒープ領域の変化を測定することです。重要なのはgetFreeMemory()GCの実行要求し、報告された空きヒープサイズが安定するのを待つキーです。上記の出力は次のとおりです。

nested:        160000 each=16
static nested: 160000 each=16

これは、アライメントの動作と可能なヒープブロックヘッダーのオーバーヘッドを考えると、私たちが期待していることです。

ここで受け入れられた回答に詳述されている計測方法が最も正確です。私が説明した方法は正確ですが、他のスレッドがオブジェクトを作成/破棄していない制御された条件下でのみです。


2

JavaビジュアルVMを使用するだけです。

メモリの問題をプロファイリングしてデバッグするために必要なものがすべて揃っています。

また、OQL(オブジェクトクエリ言語)コンソールも備えており、多くの便利なことを実行できます。 sizeof(o)


2

JetBrains IntelliJを使用する場合は、最初に[ファイル]メニューの[メモリエージェントのアタッチ]を有効にします。設定| ビルド、実行、展開| デバッガ。

デバッグする場合は、目的の変数を右クリックして、[保持サイズの計算]を選択します。 保持サイズの計算


1

私の答えは、ニックが提供したコードに基づいています。このコードは、シリアル化されたオブジェクトによって占有されている合計バイト数を測定します。したがって、これは実際にシリアライゼーションスタッフ+プレーンオブジェクトのメモリフットプリントを測定します(たとえばint、単にシリアライズすると、シリアライズされたバイトの合計量は異なります4)。したがって、オブジェクトに正確に使用される生のバイト数を取得したい場合は、そのコードを少し変更する必要があります。そのようです:

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectSizeCalculator {
    private Object getFirstObjectReference(Object o) {
        String objectType = o.getClass().getTypeName();

        if (objectType.substring(objectType.length()-2).equals("[]")) {
            try {
                if (objectType.equals("java.lang.Object[]"))
                    return ((Object[])o)[0];
                else if (objectType.equals("int[]"))
                    return ((int[])o)[0];
                else
                    throw new RuntimeException("Not Implemented !");
            } catch (IndexOutOfBoundsException e) {
                return null;
            }
        }

        return o;
    } 

    public int getObjectSizeInBytes(Object o) {
        final String STRING_JAVA_TYPE_NAME = "java.lang.String";

        if (o == null)
            return 0;

        String objectType = o.getClass().getTypeName();
        boolean isArray = objectType.substring(objectType.length()-2).equals("[]");

        Object objRef = getFirstObjectReference(o);
        if (objRef != null && !(objRef instanceof Serializable))
            throw new RuntimeException("Object must be serializable for measuring it's memory footprint using this method !");

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(o);
            oos.close();
            byte[] bytes = baos.toByteArray();

            for (int i = bytes.length - 1, j = 0; i != 0; i--, j++) {
                if (objectType != STRING_JAVA_TYPE_NAME) {
                    if (bytes[i] == 112)
                        if (isArray)
                            return j - 4;
                        else
                            return j;
                } else {
                    if (bytes[i] == 0)
                        return j - 1;
                }
            }
        } catch (Exception e) {
            return -1;
        }

        return -1;
    }    

}

私はこのソリューションをプリミティブ型、文字列、およびいくつかの簡単なクラスでテストしました。対象外の場合もございます。


更新:配列オブジェクトのメモリフットプリント計算をサポートするように例が変更されました。


0

(jmapなどを使用して)ヒープダンプを生成し、出力を分析してオブジェクトサイズを見つけることができます。これはオフラインのソリューションですが、浅いサイズや深いサイズなどを調べることができます。


0
long heapSizeBefore = Runtime.getRuntime().totalMemory();

// Code for object construction
...
long heapSizeAfter = Runtime.getRuntime().totalMemory();
long size = heapSizeAfter - heapSizeBefore;

sizeを指定すると、オブジェクトの作成によるjvmのメモリ使用量が増加します。これは通常、オブジェクトのサイズです。


オブジェクト構築のための//コードの途中でGCが実行されるとどうなりますか?これで、常に正しい結果が得られる可能性があります。
rajugaadu 2014年

0

この答えはオブジェクトのサイズとは関係ありませんが、オブジェクトを収容するために配列を使用している場合。オブジェクトに割り当てるメモリサイズ。

したがって、これらのすべてのコレクションを配列、リスト、またはマップしても、オブジェクトは実際には格納されません(プリミティブのときのみ、実際のオブジェクトメモリサイズが必要です)。これらのオブジェクトの参照のみが格納されます。

Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection

  • (4/8バイト)は(32/64ビット)OSに依存

プリミティブ

int   [] intArray    = new int   [1]; will require 4 bytes.
long  [] longArray   = new long  [1]; will require 8 bytes.

オブジェクト

Object[] objectArray = new Object[1]; will require 4 bytes. The object can be any user defined Object.
Long  [] longArray   = new Long  [1]; will require 4 bytes.

つまり、すべてのオブジェクトREFERENCEに必要なメモリは4バイトだけです。文字列参照またはダブルオブジェクト参照の場合がありますが、オブジェクトの作成に応じて、必要なメモリは異なります。

例)以下のクラスのオブジェクトを作成すると、ReferenceMemoryTest4 + 4 + 4 = 12バイトのメモリが作成されます。参照を初期化しようとすると、メモリが異なる場合があります。

 class ReferenceMemoryTest {
    public String refStr;
    public Object refObj;
    public Double refDoub; 
}

したがって、オブジェクト/参照配列を作成しているとき、その内容はすべてNULL参照で占められます。また、各参照には4バイトが必要であることを知っています。

最後に、以下のコードのメモリ割り当ては20バイトです。

ReferenceMemoryTest ref1 = new ReferenceMemoryTest(); (4(ref1)+ 12 = 16バイト)ReferenceMemoryTest ref2 = ref1; (4(ref2)+ 16 = 20バイト)


1
4バイト整数とサイズが不明なオブジェクト参照を4バイトに合わせるにはどうすればよいですか?
ローン侯爵

@EJPつまり、すべてのオブジェクトREFERENCEに必要なメモリは4バイトだけです。文字列参照またはダブルオブジェクト参照の場合がありますが、オブジェクトの作成に応じて、必要なメモリは異なります。
Kanagavelu Sugumar

0

次のComplexような名前のクラスを宣言するとします。

public class Complex {

    private final long real;
    private final long imaginary;

    // omitted
}

このクラスのライブインスタンスに割り当てられているメモリの量を確認するには:

$ jmap -histo:live <pid> | grep Complex

 num     #instances         #bytes  class name (module)
-------------------------------------------------------
 327:             1             32  Complex

-5

JSONObjectの場合、以下のコードが役立ちます。

`JSONObject.toString().getBytes("UTF-8").length`

サイズをバイト単位で返します

ファイルに書き込むことで、JSONArrayオブジェクトで確認しました。オブジェクトサイズを与えています。


これは、ほとんどが文字列であるオブジェクトに対してのみ機能します。
デクスターレガスピ

-6

一度だけ実行し、将来の使用のために保存したい場合を除いて、プログラムで実行したいとは思いません。これはコストがかかることです。Javaにはsizeof()演算子はありません。存在したとしても、他のオブジェクトへの参照のコストとプリミティブのサイズのみをカウントします。

あなたがそれを行うことができる1つの方法は、物事をファイルにシリアル化し、次のようにファイルのサイズを見ることです:

Serializable myObject;
ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("obj.ser"));
oos.write (myObject);
oos.close ();

もちろん、これは各オブジェクトが別個であり、他のものへの非一時的な参照が含まれていないことを前提としています。

別の戦略は、各オブジェクトを受け取り、リフレクションによってそのメンバーを調べ、サイズ(ブール&バイト= 1バイト、短い&char = 2バイトなど)を合計して、メンバーシップ階層を下っていく方法です。しかし、これは面倒で費用がかかり、最終的にはシリアライゼーション戦略と同じことを行うことになります。


3
ByteArrayOutputStreamを使用して、byte []に​​シリアル化します。ファイルに書き込むよりもはるかに高速です。
ScArcher2 2008

@KorayTugayオブジェクトのバイトサイズの決定は、すでにコストのかかる操作です。サイズを決定するために各オブジェクトをディスクに書き込んで、それをクロールさせます...
HammerNL

1
シリアル化されたオブジェクトの形式は、ヒープメモリ内のオブジェクトの形式とはまったく異なります。最も注目すべきは、オブジェクトのクラス(およびそのシリアライズ可能なスーパークラスのすべて)の記述子がストリームに書き込まれることです。したがって、の単純なインスタンスを書き込むと、java.lang.Integer約80バイトが生成されます。ヒープ表現は通常32です(オブジェクトストリーム表現とは異なり、ヒープ表現はポインターサイズとオブジェクトの配置に依存します)。対照的に、シリアル化されたnull参照では、ヒープメモリに4バイトまたは8バイトではなく1バイトが必要です。
Holger、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.