大量のメモリを必要とするプログラムを開発しており、メモリ不足の例外が発生したときにキャッチしたいと考えています。これは不可能だと聞いていましたが、この点について何か進展があるかどうか知りたいです。
9 に答える
例外ではありません。エラーです: java.lang.OutOfMemoryError
Throwable から派生したものをキャッチできます。
try {
// create lots of objects here and stash them somewhere
} catch (OutOfMemoryError E) {
// release some (all) of the above objects
}
ただし、かなり具体的なこと (たとえば、特定のコード セクション内に大量のものを割り当てるなど) を行っていない限り、どこからスローされるかわからないため、キャッチできない可能性があります。
それが可能だ:
try {
// tragic logic created OOME, but we can blame it on lack of memory
} catch(OutOfMemoryError e) {
// but what the hell will you do here :)
} finally {
// get ready to be fired by your boss
}
OutOfMemoryError (OOM) 例外をキャッチして回復を試みることはできますが、それはおそらく悪い考えです...特に、アプリケーションが「続行」することを目的としている場合。
これにはいくつかの理由があります。
他の人が指摘しているように、メモリ リソースを管理するには、明示的に解放するよりも優れた方法があります。つまり、メモリが不足している場合に解放できるオブジェクトに SoftReference と WeakReference を使用します。
何かを解放する前に、実際にメモリがなくなるまで待つと、アプリケーションはガベージ コレクタの実行により多くの時間を費やす可能性があります。JVM のバージョンと GC チューニング パラメータに応じて、JVM は、OOM をスローするポイントに近づくにつれて、より頻繁に GC を実行することになります。スローダウンは (アプリケーションが有用な作業を行っているという点で) 重大な場合があります。おそらくこれを避けたいでしょう。
問題の根本的な原因がメモリ リークである場合、OOM をキャッチして回復しても、リークしたメモリが回収されない可能性があります。あなたのアプリケーションは少しの間継続し、その後 OOM を何度も何度も何度も間隔を縮めながら続けます。
したがって、私のアドバイスは、OOMから継続しようとしないことです...あなたが知っている場合を除きます:
- OOM が発生した場所と理由
- 「巻き添え被害」が発生しないこと、および
- 回復が続行するのに十分なメモリを解放することを確認してください。
なぜ誰かがメモリ不足になっているのかを考えているすべての人のために、これを投げるだけです。私は頻繁にメモリ不足になるプロジェクトに取り組んでおり、これに対する解決策を実装する必要がありました。
このプロジェクトは、フォレンジックおよび調査アプリのコンポーネントです。現場でデータを収集した後 (非常に少ないメモリ フットプリントを使用)、調査アプリでデータが開かれます。機能の 1 つは、フィールド (物理メモリからのアプリケーション) でキャプチャされた任意のバイナリ イメージの CFG トラバーサルを実行することです。これらのトラバーサルには長い時間がかかる場合がありますが、トラバースされたバイナリの非常に役立つ視覚的表現を生成します。
トラバーサル プロセスを高速化するために、できるだけ多くのデータを物理メモリに保持しようとしますが、バイナリが大きくなるにつれてデータ構造が大きくなり、すべてをメモリに保持することはできません (目標は、256m 未満の Java ヒープを使用することです)。それで私は何をしますか?
LinkedLists、Hashtables などのディスク バックアップ バージョンを作成しました。これらは対応するもののドロップイン置換であり、すべて同じインターフェイスを実装しているため、外の世界からは同一に見えます。
違い?これらの置換構造は相互に連携して、メモリ エラーを検出し、最も使用頻度の低いコレクションから最も使用頻度の低い要素をメモリから解放するように要求します。要素を解放すると、一時ファイル (システムが提供する一時ディレクトリ内) のディスクにダンプされ、適切なコレクションでプレースホルダー オブジェクトが「ページアウト」としてマークされます。
Java アプリでメモリ不足になる理由はたくさんあります。これらの理由のほとんどの根本原因は、次のいずれかまたは両方です。 ) 2. アプリは単に大量のメモリを必要とします (画像編集が提案されましたが、オーディオとビデオはどうですか? 私の場合のようなコンパイラはどうですか? 不揮発性ストレージのない長期データ コレクタはどうですか?)
-少し
をキャッチすることは可能OutOfMemoryError
ですが、定義された動作を取得する方法がError
ないException
ことに注意してください。
キャッチしようとしている間に別の OutOfMemoryError が発生することさえあります。
したがって、より良い方法は、メモリを意識したキャッシュを作成/使用することです。そこにはいくつかのフレームワークがあります (例: JCS ) が、 SoftReferenceを使用して独自のフレームワークを簡単に構築できます。ここに使用方法に関する小さな記事があります。詳細については、記事内のリンクをたどってください。
大きすぎる可能性のあるものを具体的に割り当てている場合は、OutOfMemoryError をキャッチするのに適したタイミングが少なくとも 1 度はあります。
public static int[] decode(InputStream in, int len) throws IOException {
int result[];
try {
result = new int[len];
} catch (OutOfMemoryError e) {
throw new IOException("Result too long to read into memory: " + len);
} catch (NegativeArraySizeException e) {
throw new IOException("Cannot read negative length: " + len);
}
...
}
可能ですが、ヒープが不足するとあまり役に立ちません。解放できるリソースがある場合は、そのようなリソースに対して SoftReference または WeakReference を使用すると、それらのクリーンアップが自動的に行われます。
なんらかの理由で GC が自動的にトリガーされなくなる前に、ダイレクト メモリが不足した場合に役立つことがわかりました。そのため、直接バッファの割り当てに失敗した場合、gc を強制する原因がありました。
任意の例外をキャッチすることができます。書くだけ
try{
// code which you think might throw exception
}catch(java.lang.Throwable t){
// you got the exception. Now what??
}
理想的には、java.lang.Error
例外をキャッチしないことになっています。このような例外をキャッチせず、アプリケーションを終了させることが、発生した場合の最善の解決策になる場合があります。そのようなエラーを非常にうまく処理できると思われる場合は、先に進んでください。
確かに、OutOfMemoryError をキャッチすることは許可されています。そうなったときにどうするか、しっかりと計画をたてておきましょう。オブジェクトをさらに割り当てる前に、(オブジェクトへの参照をドロップして) いくらかのメモリを解放する必要があります。そうしないと、再びメモリ不足になります。スタックを数フレーム巻き戻すだけでそれができる場合もあれば、より明示的なことを行う必要がある場合もあります。