web-dev-qa-db-ja.com

Javaでメモリ不足の例外をキャッチすることは可能ですか?

私は大量のメモリを必要とするプログラムを開発していますが、メモリ不足の例外が発生したときにキャッチしたいです。これを行うことは不可能だと聞いていましたが、この目的で何か開発があったら興味があります。

51
jy.

例外ではありません。エラー: Java.lang.OutOfMemoryError

あなたはcanそれがThrowableから下降するときにそれをキャッチします:

try {
    // create lots of objects here and stash them somewhere
} catch (OutOfMemoryError E) {
    // release some (all) of the above objects
}

ただし、(たとえば、特定のコードセクション内に大量の物を割り当てるなど)かなり具体的なことを行わない限り、どこからスローされるかわからないため、キャッチすることはできません。

83
ChssPly76

それが可能だ:

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
}
53
Suraj Chandran

OutOfMemoryError(OOM)例外をキャッチして回復を試みることができます。BUT IT IS PROBABLY A BAD IDEA ...立ち止まるな"。

これにはいくつかの理由があります。

  1. 他の人が指摘しているように、メモリリソースを管理するには、明示的に解放するよりも良い方法があります。つまり、メモリが不足している場合に解放できるオブジェクトにSoftReferenceとWeakReferenceを使用します。

  2. 実際にメモリを使い果たすまで待ってから解放すると、アプリケーションはガベージコレクタの実行により多くの時間を費やすことになります。 JVMのバージョンとGCチューニングパラメータに応じて、JVMはOOMをスローするポイントに近づくにつれて、GCをより頻繁に実行することになります。スローダウン(アプリケーションが有用な作業を行っているという点で)は重大な場合があります。おそらくこれを避けたいでしょう。

  3. 問題の根本原因がメモリリークである場合、OOMをキャッチして回復してもリークしたメモリが回収されない可能性があります。アプリケーションは、OOMを少しずつ続け、何度も何度も何度も繰り返します。

だから私のアドバイスは、OOMから続けようとすることではありません...あなたがknowでない限り:

  • oOMが発生した場所と理由、
  • 「副次的損害」が発生しないこと、および
  • リカバリが続行するのに十分なメモリを解放すること。
25
Stephen C

誰かがメモリを使い果たしている理由を熟考するすべての人のためにこれを投げ捨てます:私は頻繁にメモリを使い果たすプロジェクトに取り組んでおり、このためのソリューションを実装しなければなりませんでした。

プロジェクトは、フォレンジックおよび調査アプリのコンポーネントです。フィールドでデータを収集した後(非常に低いメモリフットプリントを使用)、データは調査アプリで開かれます。機能の1つは、フィールド(物理メモリからのアプリケーション)でキャプチャされた任意のバイナリイメージのCFGトラバーサルを実行することです。これらのトラバースには時間がかかる場合がありますが、トラバースされたバイナリの非常に役立つ視覚的表現が生成されます。

トラバーサルプロセスを高速化するために、物理メモリにできるだけ多くのデータを保持しようとしますが、バイナリが大きくなるとデータ構造が大きくなり、メモリにすべてを保持することはできません(目標はJava 256m未満のヒープ)。だから私は何をしますか?

linkedLists、Hashtablesなどのディスクバックアップバージョンを作成しました。これらは対応するもののドロップイン置換であり、すべて同じインターフェイスを実装しているため、外からは同じように見えます。

違い?これらの置換構造は互いに協力して、メモリ不足エラーをキャッチし、最も使用頻度の低いコレクションから最も使用頻度の低い要素をメモリから解放するよう要求します。エレメントを解放すると、一時ファイル(システムが提供する一時ディレクトリ)のディスクにダンプし、プレースホルダーオブジェクトを適切なコレクションの「ページアウト」としてマークします。

Java app-これらの理由のほとんどのルートは、次のいずれかまたは両方です。1.リソースが制約されたマシンで実行されるアプリ(またはヒープサイズを制限することでリソースの使用を制限しようとします)2.アプリは単に大量のメモリを必要とします(画像編集が推奨されますが、オーディオとビデオはどうですか?私の場合のようなコンパイラはどうですか?非長期的データコレクターはどうですか?揮発性ストレージ?)

-ビット

14
bitflung

OutOfMemoryErrorErrorではなくExceptionです)をキャッチすることは可能ですが、定義された動作を取得する方法がないことに注意してください。
キャッチしようとすると、別のOutOfMemoryErrorを受け取ることさえあります。

したがって、より良い方法は、メモリ対応キャッシュを作成/使用することです。いくつかのフレームワークがあります(例: [〜#〜] jcs [〜#〜] )が、 SoftReference を使用して簡単に独自のフレームワークを構築できます。使用方法に関する小さな記事があります here 。詳細については、記事のリンクを参照してください。

8
Hardcoded

おそらく大きすぎるかもしれない何かを具体的に割り当てているとき、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);
  }
  ...
}
5
Adam Goode

可能ですが、ヒープを使い果たした場合はあまり役に立ちません。解放できるリソースがある場合は、そのようなリソースに対してSoftReferenceまたはWeakReferenceを使用すると、クリーンアップが自動的に行われます。

何らかの理由でGCが自動的にトリガーされない前に、ダイレクトメモリが不足すると便利です。そのため、ダイレクトバッファの割り当てに失敗した場合にgcを強制する原因がありました。

3
Peter Lawrey

Any例外をキャッチできます。書くだけ

try{
   // code which you think might throw exception
}catch(Java.lang.Throwable t){
   // you got the exception. Now what??
}

理想的には、キャッチすることにならないJava.lang.Error例外。そのような例外をキャッチせず、アプリケーションを終了させるのが、それらが発生した場合の最良の解決策かもしれません。このようなエラーを非常にうまく処理できると思われる場合は、先に進んでください。

2
jai

もちろん、OutOfMemoryErrorのキャッチは許可されています。それが起こったときに何をすべきかの計画を持っていることを確認してください。さらにオブジェクトを割り当てる前に、(オブジェクトへの参照を削除することにより)メモリを解放する必要があります。そうしないと、メモリが不足します。時には、スタックを数フレームだけ巻き戻すだけの行為があなたのためにそれをすることがあり、時にはより明確な何かをする必要があります。

1
Keith Randall