2009-08-27 15 views
2

例外がスローされたり、プログラムが正常に終了することなく、Javaプロガムが突然終了する問題があります。明白な理由なしにJava VMが突然終了する

私はProject Euler14th problemを解決するプログラムを書いています。これは私が得たものである:私はキャッシュを追加することによって、最適化したかったので、私は変更

private static final int INITIAL_CACHE_SIZE = 30000; 
private static Map<Long, Integer> cache = new HashMap<Long, Integer>(INITIAL_CACHE_SIZE); 

public void main(String... args) { 
    long number = 0; 
    int maxSize = 0; 

    for (long i = 1; i <= TARGET; i++) { 
     int size = size(i); 
     if (size > maxSize) { 
      maxSize = size; 
      number = i; 
     } 
    } 
} 
private static int size(long i) { 
    if (i == 1L) { 
     return 1; 
    } 
    final int size = size(process(i)) + 1; 
    return size; 
} 

private static long process(long n) { 
    return n % 2 == 0 ? n/2 : 3*n + 1; 
} 

これは正常に動作し、1 000 000

のTARGETを使用した場合、約5秒で正常終了しますこれにサイズ方法:私はそれを実行したとき、私は555144.同じ番号にするたびに取得するときに

private static int size(long i) { 
    if (i == 1L) { 
     return 1; 
    } 
    if (cache.containsKey(i)) { 
     return cache.get(i); 
    } 
    final int size = size(process(i)) + 1; 
    cache.put(i, size); 
    return size; 
} 

は今、それは単に(プロセスが終了)を停止します。例外、エラー、Java VMクラッシュなど何もスローされません。

キャッシュサイズを変更しても効果がないようですが、キャッシュ でこのエラーがどのように発生するのですか?

私は初期のが、そうのような永続的なだけではないようにキャッシュサイズを強制した場合:

if (i < CACHE_SIZE) { 
     cache.put(i, size); 
    } 

バグが発生しなくなりました。 編集:2Mのようにキャッシュサイズを設定すると、バグが再び表示され始めます。

誰でもこれを再現できますか、それが起こる理由についての提案を提供することもできますか?

+0

あなたはどのOSで実行していますか? –

+0

私はWindows Vista BusinessとJDK 1.6.0_03を実行しています – Jorn

+0

jdkを更新して、同じ動作をするかどうかを確認してください。彼らは今更新16から1.6になっています。 – digitaljoel

答えて

8

これは単純に印刷されていないOutOfMemoryErrorがあります。高いヒープサイズを設定するとプログラムは正常に動作します。それ以外の場合は、ログに記録されていないOutOfMemoryError(デバッガでは見やすい)で終了します。

あなたはこれを確認し、このJVMの引数を渡すと、あなたのプログラムを再実行してヒープ・ダンプ(同様のOutOfMemoryErrorが発生したことをプリントアウト)を取得することができます。これにより

-XX:+HeapDumpOnOutOfMemoryError

それがその後、何かを出力しますアップバンプ

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid4192.hprof ...
Heap dump file created [91901809 bytes in 4.464 secs]

ヒープサイズと、たとえば、-Xmx200mとあなたが問題を持っていない - 少なくともTARGET = 1000000のために:この効果に。

+0

うん、あなたは正しい。そのコマンドライン引数は、OutOfMemoryErrorを示しました。 – Jorn

0

Javaプロセスが突然クラッシュすると、一部のリソースが最大になってしまう可能性があります。記憶のように。最大ヒープをより高く設定しようとする可能性があります。

+0

それはそれだとは思わない。 OutOfMemoryExceptionsを投げているわけではありません。また、Windowsタスクマネージャーは、100 MB以上のメモリを使用していないと伝えています。 – Jorn

+0

それは100MBを超えて使用していないかもしれませんが、本当に巨大なメモリ(割り当てられていないのでタスクマネージャには表示されません)を割り当てようとすると、 OutOfMemoryExceptionsの欠如についてのあなたの主張は、このシナリオにはまったく適合しませんが... – rmeador

+1

私はこれを試しました。私はそれを再現することができます。 Javaのexeプロセスはエラーコード1をOSに戻しています。ハッシュマップの再ハッシングにバグがあると思われます。私はSunのJDK 1.6.0_16にあります –

0

クラッシュ後にヒープダンプが生成されていますか?このファイルはJVM用のカレントディレクトリになければなりません。それは私が詳細を探す場所です。

+0

いいえ、並べ替えの何も。 – Jorn

+0

終了時に、argを渡さずに自動的にヒープダンプは生成されません。他の方法もありますが、この特殊なケースでは、-XX:+ HeapDumpOnOutOfMemoryError –

+0

ヒープダンプは自動的に生成されますが、実際のVMのクラッシュではなく、OutOfMemoryErrorsではなくVMの実装間でも動作が可能です。 – Yishai

0

Cache.put(i、size)でOutOfMemoryエラーが発生しました。

エラーをデバッグモードを使用してeclipseで実行するには、デバッグウィンドウにエラーが表示されます。コンソールにスタックトレースは生成されません。

3

JVM自体がクラッシュしたように聞こえます(これは、プログラムが何らかの例外を知らずに死んだときの最初の考えです)。このような問題の第一歩は、ご使用のプラットフォームの最新リビジョンにアップグレードすることです。 JVMは、ユーザー・レベルにそのディレクトリーへのアクセス権があると仮定して、JVMを開始したディレクトリーの.logファイルにヒープをダンプする必要があります。

OutOfMemoryエラーの中には、メインスレッドで報告されないものがあるため、try/catch(Throwable t)を実行して取得しない限り、実際にはメモリが不足しています。 100MBしか使用していないという事実は、JVMがより多くを使用するように設定されていないことを意味します。これは、JVMの起動オプションを-Xmx1024mに変更してメモリのギグを取得し、問題がどこにあるかを確認することで変更できます。

トライキャッチを行うためのコードは次のようなものでなければなりません:

public static void main(String[] args) { 
    try { 
     MyObject o = new MyObject(); 
     o.process(); 
    } catch (Throwable t) { 
     t.printStackTrace(); 
    } 
} 

とプロセスの方法ですべてを行うとエラーがcatchステートメントで発生した場合、静的にそのように、あなたのキャッシュを保存しませんオブジェクトはスコープ外にあり、ガベージコレクトすることができ、スタックトレースの印刷を可能にするのに十分なメモリが解放されます。そのことが保証されているわけではありませんが、それはより良い結果をもたらします。

+0

問題はOutOfMemoryErrorです。ハッシュマップが特定のサイズを超えると、ハッシュマップを再ハッシュするスレッド内にある可能性があります。 –

+0

これは別のスレッドでは発生しません。 –

0

再帰的なサイズ()メソッドは、おそらくキャッシュを行うには良い場所ではありません。私はcache.put(i、size)を呼び出します。 main()のfor-loopの内側にあり、はるかに迅速に動作します。それ以外の場合は、OOMエラー(ヒープスペースがなくなる)も発生します。

編集:ここではソースだ - キャッシュ検索は))(サイズであるが、記憶が(メインで行われます。

public static void main(String[] args) { 
    long num = 0; 
    int maxSize = 0; 

    long start = new Date().getTime(); 
    for (long i = 1; i <= TARGET; i++) { 
     int size = size(i); 
     if (size >= maxSize) { 
      maxSize = size; 
      num = i; 
     } 
     cache.put(i, size); 
    } 

    long computeTime = new Date().getTime() - start; 
    System.out.println(String.format("maxSize: %4d on initial starting number %6d", maxSize, num)); 
    System.out.println("compute time in milliseconds: " + computeTime); 
} 

private static int size(long i) { 
    if (i == 1l) { 
     return 1; 
    } 

    if (cache.containsKey(i)) { 
     return cache.get(i); 
    } 

    return size(process(i)) + 1; 
} 

サイズからcache.put()()の呼び出しを削除することによって、それはすべての計算されたサイズをキャッシュしませんが、それはまた再キャッシュする以前に計算されたサイズ避けることに注意してください。これはハッシュマップ操作には影響しませんが、akfが指摘したように、ヒープ・キラーがどこから来ているのかを示すオートボクシング/アンボクシング操作は避けられます。私はsize()でも "if(!containsKey(i)){cache.put()etc"を試みましたが、残念ながらメモリが足りなくなりました。 size(long i)の2 implmentations間

1

大きな違いの1つは、作成するオブジェクトの量です。最初の実装では

、作成中の何Objectsはありません。第二に、あなたは、オートボクシングの非常に多くをやって、あなたのキャッシュの各アクセスのための新しいLongを作成し、各修正にLong sおよび新しいIntegerの新しいに入れています。

これは、メモリ使用量の増加ではなくOutOfMemoryErrorの不在を説明するだろう。ヒープを増やすことで、それは私のために完了することができます。 this Sun aritcleから

The performance ... is likely to be poor, as it boxes or unboxes on every get or set operation. It is plenty fast enough for occasional use, but it would be folly to use it in a performance critical inner loop.

+0

メモリ使用量の増加はおそらくOOMにつながっています。ガベージコレクタが未使用のオブジェクトを解放する前に、高速オブジェクト生成がメモリを覚ますと推測しています。 – weiji

関連する問題