Javaメモリオーバーヘッド
質問
Javaのメモリオーバーヘッドについて尋ねたいと思います。私は大きなアレイリスト(61,770アイテム)を持っています(各アイテムが撮影したメモリの量(オブジェクトとその配列エントリをカウント)を計算しようとします。アプリをプロファイリングすることによりすべてのデータがロードされた後、ヒープには〜25MBが必要です。 ArrayListに2つのアイテムしかない場合、ヒープには〜1MBがかかるため、大まかに:
(24*1024*1024)/61,768 = 407バイト。
でも, 、各オブジェクトのフィールドをカウントすると、148バイト(ArrayListを含めないで、int = 4、float = 4、参照= 4)を取得します。 ...
ArrayListに保存しているオブジェクトがインターフェイスを実装しているため、追加の値を保存し、VMが実装された各メソッドに4byte関数ポインターを保存するのでしょうか?それらが実装するインターフェイスには20の関数があるため、測定された400バイトにまだ近くはありません。
どんな助けも感謝します。
うわー、すべての素晴らしい答えに感謝します。
@Bolo:リンクをありがとう、このクラスIを使用して、オブジェクトごとに約350バイトを測定しているため、大きなメモリ使用量のソースを最も確認できます。
@yuval A:貴重な情報源であるそのプレゼンテーションをありがとう。
@ukko:ポイントが指摘した。
@Jayan:NetBeansプロファイラーは、ヒープを捨てようとするとエラーを与えています。後でもう一度試してみます。
解決
これらの結果は驚くことではありません。 JVMは、各オブジェクトに膨大な量のオーバーヘッドを追加します。
JVMメモリオーバーヘッドのため、単一のオブジェクトの予想サイズの約2倍は珍しくありません。
このプレゼンテーション Javaのさまざまなデータ構造メモリ使用量の素晴らしい、詳細な説明と概要があります。
他のヒント
アレイリストは、要素の数よりもほとんど大きいです。使用する getCapacity()
基礎となる配列の現在のサイズを取得します。
あなたのアプローチの大きな問題は、ゴミコレクターとの相互作用です。基本的には、外部から完全に不透明なことを提案したように、あらゆるテストを行います。
これをやりたいなら、思考実験として
- JVMを起動し、いくつかのグローバルGCSを実行してすべてのジャンクを取り出します
- ヒープのサイズとJavaの概念を測定します。
- テストを実行します
- GCは数回
- ステップ#2から測定値をやり直します
結局のところ、少しの数学の後、あなたはより近くになりますが、それでも正しくありません。唯一の本当の解決策は、他の人が言及したように実際に実装を尋ねることです。または、実装の知識からそれを把握します。
ArrayListによって消費されるメモリは少しあいまいです。
適切な段階でプロセスのヒープダンプを取得します - 値が完全に割り当てられた後。次に、メモリアナライザー(Eclipseから)などのツールを使用します。
浅く保持されているヒープサイズを見つけます。
サイドノートとして、ArrayListにいくつのオブジェクトがあるかを正確に知っているので、Array []を使用してみませんか?そこにあるオブジェクトの数は変わりますか?