私はまだJavaのロープを学んでいます。これに対する明らかな答えがあれば申し訳ありません。大量のメモリを使用しているプログラムがあり、その使用量を減らす方法を考えたいです。しかし、多くのSOの質問を読んだ後、最適化を開始する前に問題の場所を証明する必要があるという考えがあります。
だからここに私がやったこと、プログラムの開始にブレークポイントを追加して実行した後、visualVMを起動してメモリのプロファイルを作成しました(結果を比較するために同じことをNetBeansでも行いましたが、それらは同じです)。私の問題は、それらの読み方がわからないことです。char[]
と私はコードも何も見ることができません(visualvmはjvmに接続していて、ソースを見ることができないので理にかなっていますが、netbeansはCPUプロファイリングを行うときのようにソースも表示しません)。
基本的に私が知りたいのは、どの変数(そしてできればどのメソッドのような詳細)がすべてのメモリが使用されているので、そこで作業に集中できることです。これを行う簡単な方法はありますか?私は現在、EclipseとJavaを使用して開発しています(そして、プロファイリング専用のvisualVMとnetbeansをインストールしましたが、この仕事が完了すると思うものは何でもインストールします)。
編集:理想的には、すべてのオブジェクトを取得し、サイズでソートするものを探しています(だから、どれがメモリを占有しているのかを見ることができます)。現在、string []やint []などの一般的な情報を返しますが、どのオブジェクトを参照しているかを知りたいので、サイズを最適化する作業に取り掛かります。
文字列には問題があります
基本的に、Javaでは、String
参照(舞台裏でchar[]
を使用するもの)がメモリ(賢明な)ほとんどのbusinessアプリケーションを支配します。作成方法によって、JVMで消費するメモリ量が決まります。
それは、データ型としてほとんどのビジネスアプリケーションにとって非常に基本的であり、メモリ消費量が最も多いためです。これは単なるJava事、String
データ型は、ほとんどすべての言語とランタイムライブラリで多くのメモリを占有します。 1文字あたり1バイト、またはそれより悪い場合(Unicode)は、1文字あたり複数バイトの配列です。
Oracle JDBC依存関係もあるWebアプリでCPU使用率をプロファイリングすると、StringBuffer.append()
が他のすべてのメソッド呼び出しよりも桁違いにCPUサイクルを支配していることがわかりましたcombined、その他の単一のメソッド呼び出し。 JDBCドライバーは、多くのString
操作を行いましたが、すべてにPreparedStatements
を使用することのトレードオフのようなものです。
あなたが心配しているものは、直接ではなく、制御できない
焦点を合わせる必要があるのは、コントロール内の内容です。これにより、必要以上に長い参照を保持しないようにし、不必要に物を複製しないようにします。 Javaのガベージコレクションルーチンは高度に最適化されており、アルゴリズムの動作方法を学習すれば、それらのアルゴリズムが動作するための最適な方法でプログラムが動作することを確認できます。
Javaヒープメモリは他の言語の手動管理メモリとは異なり、これらのルールは適用されません
他の言語のメモリリークと見なされるものは、Javaそのゴミと同じもの/根本的な原因ではありません収集システム。
ほとんどの場合、Javaメモリは、リークしている単一のuber-objectによって消費されません(他の環境では参照がぶら下がります))。
StringBuffer
/StringBuilder
オブジェクトが最初のインスタンス化で適切なサイズになっていないため、後続のappend()
呼び出しを保持するためにchar[]
配列を自動的に拡張する必要があるため、多くの小さな割り当てが発生する可能性が高くなります。
これらの中間オブジェクトは、スコープと実行時に変化する可能性のある他の多くの理由により、ガベージコレクターによって予想されるよりも長く保持される場合があります。
例:ガベージコレクターは候補があると判断する可能性がありますが、まだ十分なメモリがあると見なしているため、その時点でそれらをフラッシュするには時間がかかりすぎる可能性があります、メモリの負荷が高くなるまで待機します。
ガベージコレクターは現在非常に優れていますが、魔法ではありません。退化する場合、最適に動作しなくなります。 JVMのすべてのバージョンのガベージコレクター設定に関する多くのドキュメントがインターネット上にあります。
これらの参照されていないオブジェクトは、ガベージコレクターがメモリから消去するために必要であると考える時間に達していないか、他のオブジェクト(List
)によって保持されているオブジェクトへの参照がある可能性がありますあなたがまだそのオブジェクトを指していることに気付いていない例。これは、最も一般的にJavaでleakと呼ばれるもので、より具体的には参照リークです。
例:String
を使用して4K StringBuilder
を構築する必要があることがわかっている場合、デフォルトではなくnew StringBuilder(4096);
で作成します。オブジェクトのサイズが賢明だと思うものを何回も表すことができるガーベッジの作成をすぐに開始します。
VisualVMでインスタンス化されたオブジェクトの種類の数を知ることができます。これにより、知っておくべきことがわかります。 「これは大きなメモリの消費者です!」という単一のクラスの単一のインスタンスを指す大きな点滅ライトはありません。つまり、いくつかのchar[]
のインスタンスが1つしかない場合を除きます。他の多くのクラスが内部でchar[]
を使用しているため、大量のファイルが含まれていますが、これも不可能です。そして、あなたはすでにそれをほとんど知っていました。
OutOfMemoryError
の言及が見当たらない
あなたはおそらくあなたのコードに問題はありません、ガベージコレクションシステムはあなたがthinkクリーンアップする必要があります。プログラムがOutOfMemoryError
でクラッシュしない限り、あなたが思うが問題ではないでしょう。これは、C、C++、Objective-C、またはその他の手動メモリ管理言語/ランタイムではありません。メモリに何があるか、またはできるはずの詳細レベルではないかを判断することはできません。
JProfiler では、ヒープウォーカーに移動して最大のオブジェクトビューをアクティブにできます。ほとんどのメモリを保持するオブジェクトが表示されます。 「保持」メモリは、オブジェクトを削除した場合にガベージコレクタによって解放されるメモリです。
その後、オブジェクトノードを開いて、保持されているオブジェクトの参照ツリーを表示できます。最大のオブジェクトビューのスクリーンショットを次に示します。
免責事項:私の会社はJProfilerを開発しています
Java JDKにはJVisualVMが付属しています。アプリケーションサーバー(たとえば、実行中)でvisualvmを実行し、localhostに接続できます。メモリ割り当てを提供し、ヒープダンプを実行できるようにします
有効にする方法の詳細な手順: http://sysdotoutdotprint.com/technologies/Java/6
ヒープダンプをキャプチャし、それらを分析できる Eclipse MAT のようなツールを使用することをお勧めします。多くの tutorials が利用可能です。 ドミネーターツリー のビューを提供して、ヒープ上のオブジェクト間の関係を洞察します。具体的には、MATの「GCルートへのパス」機能により、char []、String []、およびint []オブジェクトの大部分がどこで参照されているかがわかります。 JVisualVMは、特に割り当てスタックトレースでスナップショットを使用することにより、リークと割り当てを識別するのにも役立ちます。 プロセスのウォークスルー スナップショットを取得し、それらを比較して割り当てポイントを見つけるというかなりの数があります。
VisualVMを使用してメモリ使用量を確認する場合、メソッドではなくデータに焦点が当てられます。おそらく、あなたの大きなchar []データは多くの文字列値によって引き起こされているのでしょうか?再帰を使用していない限り、データはローカル変数からのものではありません。そのため、大きなデータ構造に要素を挿入するメソッドに集中できます。 「メモリリーク」の原因となる正確なステートメントを調べるには、さらに追加することをお勧めします