20

大量 (数百万) の存続期間の長いオブジェクトを持つアプリケーションのヒープ サイズの使用をどのように最適化しますか? (大きなキャッシュ、データベースから大量のレコードをロードする)

  • 適切なデータ型を使用する
    • 他のデータ型を表すために java.lang.String を避ける
  • オブジェクトの重複を避ける
    • 値が事前にわかっている場合は列挙型を使用します
    • オブジェクト プールを使用する
    • String.intern() (良いアイデア?)
  • 必要なオブジェクトのみをロード/保持

一般的なプログラミングまたは Java 固有の回答を探しています。ファンキーなコンパイラ スイッチはありません。

編集:

ヒープに何百万回も出現する可能性のある POJO のメモリ表現を最適化します。

ユースケース

  • 巨大な csv ファイルをメモリにロードします (POJO に変換されます)
  • Hibernate を使用してデータベースから何百万ものレコードを取得する

回答の再開:

  • フライウェイト パターンを使用する
  • コピーオンライト
  • 3 つのプロパティを持つ 10M オブジェクトをロードする代わりに、サイズが 10M の 3 つの配列 (または他のデータ構造) を持つ方が効率的ですか? (データを操作するのは面倒かもしれませんが、メモリが本当に不足している場合は...)
4

12 に答える 12

20

メモリ プロファイラーを使用して、メモリが消費されている場所を確認し、最適化することをお勧めします。定量的な情報がなければ、効果がないか、実際に事態を悪化させるものを変更することになる可能性があります。

特にオブジェクトが小さい場合は、データの表現を変更することを検討できます。たとえば、データのテーブルを、行ごとに 1 つのオブジェクトではなく、列ごとにオブジェクト配列を持つ一連の列として表すことができます。これにより、個々の行を表す必要がない場合、各オブジェクトのオーバーヘッドを大幅に節約できます。たとえば、12 列と 10,000,000 行のテーブルでは、1,000 万 (行ごとに 1 つ) ではなく、12 個のオブジェクト (列ごとに 1 つ) を使用できます。

于 2009-04-25T15:41:26.657 に答える
18

どのような物を収納しようとしているのかを言わないので、細かいアドバイスをするのは少し難しいです。ただし、いくつかの (排他的ではない) アプローチは、順不同で次のとおりです。

  • 可能な限りフライウェイト パターンを使用します。
  • ディスクへのキャッシュ。Javaには 多数のキャッシュ ソリューションがあります。
  • String.intern が良いアイデアかどうかについては、いくつかの議論があります。再質問については、こちらを参照 してください。String.intern()、およびその適合性に関する議論の量。
  • ソフト参照または参照を利用 して、必要に応じて再作成/再ロードできるデータを保存します。キャッシュ技術でソフト参照を使用する方法については、こちらを参照 してください。

保存しているオブジェクトの内部と寿命について詳しく知ると、より詳細な答えが得られます。

于 2009-04-25T15:34:07.640 に答える
11

オブジェクトモデルの適切な正規化を確認し、値を複製しないでください。

ええと、それが数百万のオブジェクトしかない場合は、まともな64ビットVMとたくさんのRAMを購入するだけだと思います;)

于 2009-04-25T15:55:11.927 に答える
4

すべての「ライブ」オブジェクトの概要が必要なため、通常の「プロファイラー」はあまり役に立ちません。ヒープダンプアナライザが必要です。Eclipseメモリアナライザーをお勧めします。

文字列で始まる重複オブジェクトを確認します。フライトウェイト、コピーオンライト、レイジー初期化などのパターンを適用できるかどうかを確認してください(グーグルがあなたの友達になります)。

于 2009-04-25T21:20:17.027 に答える
3

ここからリンクされているこのプレゼンテーションをご覧ください。一般的な Java オブジェクトとプリミティブのメモリ使用をレイアウトし、すべての余分なメモリがどこに行くのかを理解するのに役立ちます。

メモリ効率の高い Java アプリケーションの構築: 実践と課題

于 2011-09-16T19:28:19.137 に答える
2

メモリに格納するオブジェクトを減らすことができます。:) ディスクにスピルするキャッシュを使用するか、Terracotta を使用してヒープ (仮想) をクラスタ化し、未使用の部分をメモリからフラッシュして、透過的にフォールトして戻します。

于 2009-04-25T22:57:57.667 に答える
1

Peter alredyが作ったポイントに何かを追加したい(彼の答えにコメントすることはできません:()intutionで行くよりもメモリプロファイラーを使用する方が常に良いです( javaメモリプロファイラーをチェックしてください)。無視にはいくつかの問題があります。また、コレクションクラスはメモリリークを起こしやすい傾向があります。

于 2009-04-25T18:46:43.277 に答える
1

何百万もの整数や浮動小数点などがある場合は、アルゴリズムがプリミティブの配列でデータを表現できるかどうかを確認してください。つまり、各ガベージ コレクションの参照が少なくなり、CPU コストが低くなります。

于 2009-04-29T09:20:12.687 に答える
0
  1. Assign nullvariables使用されるすべての値no longer。したがってmake it available for Garbage collection
  2. De-reference the collections使用が終了すると、GCはそれらをスイープしません。
于 2010-04-06T06:38:49.643 に答える
0

VM のコマンド ライン オプション、特にガベージ コレクションに関するオプションに慣れて調整するのに時間を費やしてください。これによってオブジェクトが使用するメモリが変わることはありませんが、大量の RAM を搭載したマシンでメモリを集中的に使用するアプリのパフォーマンスに大きな影響を与える可能性があります。

于 2009-04-29T08:19:34.920 に答える
0

ファンシーな方法: ほとんどのデータを RAM で圧縮したままにします。現在のワーキング セットのみを展開します。データが適切に機能する良好な局所性を持っている場合。

より良いデータ構造を使用してください。Java の標準コレクションはかなりメモリを消費します。

【より良いデータ構造とは】

  • コレクションのソースを見ると、コレクションへのアクセス方法を制限すると、要素ごとのスペースを節約できることがわかります。
  • コレクション ハンドルが大きくなる方法は、大規模なコレクションには適していません。コピペしすぎ。大規模なコレクションの場合、btree などのブロックベースのアルゴリズムが必要です。
于 2009-04-28T21:07:50.060 に答える