2013-08-10 7 views
5

私はこのプログラムは、ブロックをキャッチするために行かない(ヒープがいっぱいになると、私は理由を理解したい)なぜそれをキャッチしようとしている間にOOMEの動作が異なるのですか?

public class OOME_NotCatch { 

    static List l = new ArrayList(); 
    static Long i = new Long(1); 

    public static void main(String[] args) { 
     try { 
      while (true) { 
       l.add(i); 
       i++; 
      } 
     } catch (OutOfMemoryError e) { 
      e.printStackTrace(); 
      System.out.println("Encountered OutOfMemoryError"); 
     } 
    } 
} 
//Console : Exception in thread "main" 

をしかし、プログラムの下の後でも、良い走る専門家

あなたからいくつかの理解を必要としますOOMEを取得する:

public class Catch_OOME_Collection { 

    static List l = new ArrayList(); 

    public static void main(String[] args) { 
     try { 
      while (true) { 
       l.add(new byte[1000000]); 
       System.out.println("size " + l.size()); 
      } 
     } catch (OutOfMemoryError e) { 
      System.out.println("Encountered OutOfMemoryError"); 
      e.printStackTrace(); 
      System.out.println("size of list is " + l.size()); 
      Iterator i = l.iterator(); 
      while(i.hasNext()){ 
       System.out.println(i.next().toString()); 
       i.remove(); 
      } 
      while (true) { 
       System.out.println("keep printing"); 
      } 
     } 
    } 
} 

私は同じエラーOOMEの異なる結果を見た後、少し混乱しています。してください。

答えて

8

私の理解では、最初のプログラムでは、わずか数バイトのメモリしか必要としない新しいLongオブジェクトを割り当てるときにOOMEがスローされます。これは、ヒープが完全にいっぱいであり、キャッチブロックを実行するために使用可能なメモリがないことを意味します。

2番目のプログラムでは、100万バイトの新しい配列を割り当てるときにOOMEがスローされます。これは失敗しますが、ヒープにはまだ999,990バイトの空きがあることを意味する可能性があります。これは、catchブロックを実行させるのに十分です。

+0

私は最初のプログラムの分析を理解していません。例外ハンドラが私のために実行されることに加えて、JVMは基本的にどのメモリも全く割り当てられない状態で、どのように起動することができますか? sysoutがフラッシュされる前にJVMがシャットダウンしていて、syserrを使用するとOPの結果が異なる可能性が高いことがわかります。 –

+0

JVMは、catchブロック内の命令を実行するためにメモリを割り当てる必要があります(スタックトレースを出力するなど)。したがって、JVMは終了します。要するに、私の答えはJoniの答えと似ていますが、第2のプログラムがJVMに利用可能なメモリを残すのはなぜですか? –

+0

さて、それは新しい「Long」を割り当てることと何が関係していますか? –

5

両方のプログラムがcatchブロックに入ります。メッセージを生成して印刷する前に、どちらかがメモリ不足になり、すぐに新しいOutOfMemoryErrorが返されます。

最初のプログラムを試すと、catchブロックが生成する出力が表示されます。これは、一度エラーがスローされると予測できないプログラムの実行がどのように表示されるかを示します。スタックトレースでは、ArrayListの新しいバッキングアレイを作成しようとしているときにOOMEがスローされたことがわかります。つまり、catchブロックを実行するのに十分なメモリが残っています。作成中にOOMEがスローされた場合は、Longオブジェクトが小さくなることがあります。

重要なことは、OutOfMemoryErrorを意味のある方法で実際に捕まえることができないということです。内部データ構造を矛盾した状態にして、非常に不都合な場所でエラーをスローすることができます。この場合、目に見える悪影響はありませんが、ArrayListの内部フィールドを調査した場合、実際にリストが変更されていない限り、modCountフィールドが増分されています。

+0

私はあなたが何を意味しているか分かりません。例外がキャッチされると、印刷するのに十分なメモリもありません。 –

+0

'e.printStackTrace()'メソッドは、メッセージを出力するために多くの文字列やその他のオブジェクトを作成する必要があります。メモリが少なくてもプログラムが実行されている場合、余分なオブジェクトを1つでも作成すると、別のOOMEが発生する可能性があります。 – Joni

+0

この例外がスローされると、プログラムは実際に何をすることができますか? –

0

Long以上を割り当てるか、おそらくは内部配列のサイズを大きくすると、最初のプログラムのメモリが不足します。

byte[1000000].を割り当てると、2番目のプログラムのメモリがほとんどなくなる可能性があります。これはおそらく、最初のプログラムの失敗の原因よりもはるかに大きなメモリであるため、既存のメモリはおそらく最初のケースでは、catchブロック内のコードは、何をするためにいくつかのStringsなどを割り当てることに成功することができます。

関連する問題