質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.99%

Javaで実装したプログラムを稼働させ続けた場合、いつかはOutOfMemoryが発生するのでしょうか?

受付中

回答 4

投稿 編集

  • 評価
  • クリップ 6
  • VIEW 647

dropttt

score 0

お世話になります。

検証作業中にふと気になったのですが、
Javaで実装したプログラムを稼働させ続けた場合、
どんなに単純なプログラムであってもいつかはそのプロセスは落ちるのでしょうか?

今回試した作業は以下になります。

●実行環境
OS:Windows 10
JDK:Amazon Corretto 8

●プログラム作成
ログを1行出力し、それを無限ループさせるプログラムを作成

class main{
    public static void main(String[] args){
        try{
            while(true){
                System.out.println("testtest");
                Thread.sleep(1);
            }
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}

●プログラム実行        
作成したプログラムを下記コマンドでコマンドプロンプトから実行

java -Xms8m -Xmx8m -Xmn2m main

●実行結果

==OOME発生寸前のログ==(約1時間半は稼働し続けていた)

testtest
testtest
testtest
testtest
testtest
testtest
testtest
testtest
testtestException in thread "RMI TCP Connection(idle)" Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded

【今回設定した条件】
①プログラムの繰り返し間隔を極端に短くして実行(1000分の1秒ごと)
②プログラムの実行引数を小さくして実行(-Xms8m -Xmx8m -Xmn2m)

ヒープサイズは小さいですが、一時間半以上稼働していたため、
プログラムの初期実行に必要な容量は割り当てられていると想定しています。

今回は検証のため、上記のような条件で実行しましたが、
妥当な値で実行したとしても長い目で見た場合にメモリの上昇によるOOMEが発生するのではないか?と思っています。

通常稼働させた場合は、何年という単位になるのかもしれませんが、
いつかは落ちるのでしょうか。。?

何かご存じの方いらっしゃいましたら、ご教示いただけますと幸いです。

宜しくお願い致します。

(追記 2019/09/24)
エラー内容がjconsoleに起因することが考えられる為、
jconsoleを使わずに処理を流してOOMEが発生しないかを検証中。

→ jconsoleによる監視を外した結果、RMI TCP Connection Exceptionは出なくなったが、
OutOfMemoryError は再発し、プロセスが落ちてしまった。

(追記 2019/09/26)

java -Xms8m -Xmx8m -Xmn2m -XX:-UseGCOverheadLimit main

オプションを付けて上記で実行しましたが、変わらずOOMEが発生して落ちてしまいました。

エラー内容
Exception in thread "main"
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+3

3.2 OutOfMemoryError例外の理解 - Oracleには以下の記載があります。

Exception in thread thread_name: java.lang.OutOfMemoryError: GC Overhead limit exceeded
原因: 「GC overhead limit exceeded」という詳細メッセージは、ガベージ・コレクタが常時実行されているため、Javaプログラムの処理がほとんど進んでいないことを示しています。ガベージ・コレクション後、Javaプロセスでガベージ・コレクションの実行に約98%を超える時間が費やされ、ヒープのリカバリが2%未満であり、その状態が直近5回(コンパイル時間定数)の連続するガベージ・コレクションで続いている場合に、java.lang.OutOfMemoryErrorがスローされます。この例外は通常、Javaヒープに新しい割当て用の空き領域がわずかしかなく、ライブ・データの容量をほとんど格納できないためにスローされます。
処置: ヒープ・サイズを増やしてください。「GC Overhead limit exceeded」のjava.lang.OutOfMemoryError例外は、コマンド行フラグ-XX:-UseGCOverheadLimitを使用すると無効にできます。

ガベージコレクタが常時実行されていることが原因のようです。ガベージコレクタの対象はコード上にはStringしかなく、これがガベージコレクタされているとは考えづらいですが、ひょっとしたら非常に短い間隔でThread.sleepしていることが原因かなと思います。そのメソッド内でスレッドを待たせるために何らかのオブジェクトを使っていないとも言えませんし。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/23 10:16

    横から失礼します
    私も見ていて気になったので試してみました。
    Eclipseのヒープ・ステータスを見ていたところ
    System.out.println("testtest")

    String text = "testtest"

    変えたら動きがほとんどなくなったためprintlnかもしれないです。
    printlnの中を掘って行ったらStringを入れ込むchar[]をnewしていたりするのでそういうのを掃除しているのかも…完全には追いきれていないので正しいところはわからないのですが。

    キャンセル

  • 2019/09/24 10:00

    なるほど... 検証頂きありがとうございます。
    今回の検証内容であれば println を変更する余地があるのかもしれませんが、
    一般的に商用環境で使用する常駐プログラムであれば、ログを1行出すだけという内容ではなく
    もっと複雑なものになると思います。。
    そうなると println に限ったことではなく、色々なライブラリ、メソッドで発生しうる可能性が増え、プログラムの常駐自体(永遠にという意味では)出来ないのではないかと思いました。

    キャンセル

  • 2019/09/26 15:46 編集

    UseGCOverheadLimitを用いてみましたが、変わらずOOMEが発生していましました..
    ヒープをあげれば稼働時間は改善されると思いますが、長い目で見たら落ちてしまうのかなと思っています。

    キャンセル

+2

新規にメモリ確保など、行っていないようなので、Out of Memoryになる要因は無いと思いますが、、、。
ただ、Windows10とか、JDKとかが、何十日も問題無く動くかが問題ですが、最近のだと、まあ、通常使用の範囲では、大丈夫かと。

何年かというと、元々がそういうシステムで無いので、誰も保証はしてくれないと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/24 10:04

    49.7日問題とか497日問題などというものもありましたし、あとはマシンの物理的なトラブルや、処理系のパッチ当てで止めざるを得ない場面も考えられますね>年単位で永続的に動かすことへの障害

    キャンセル

0

jconsole

RMIスレッドが起動しているのでjconsoleで監視しているときに限って起きるのではないでしょうか。

Exception in thread "RMI TCP Connection(idle)" Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded


真の原因はわかりませんが、サンプリングのためにメモリを使っているはず。監視なしで実行するか、できるならサンプリングを緩くするのはどうでしょう。

文字列リテラル

ちなみに、リテラル"testtest"はintern()されるので、Fly Weight型オブジェクトとして、常にひとつのインスタンスが参照されるはず。

追記 (System.out) 2019-09-23

出力バッファを疑う。

 Amazon Corretto-8.222.10.1 (build 1.8.0_222-b10) (2019-09-30) 

cmd.exeウィンドウでテストプログラムを起動、60時間以上放置しましたが正常実行しています。jcmdでクラスヒストグラムを見る限り、ヒープが安定しており、このまま放置してもOOMEは発生しないと思われます。従って、これ以上調べません。追記もしません。

気になるのは、jconsoleでテストプログラムに一度でも接続するとJVMに監視用?オブジェクトが作られ、オブジェクトが増え続けてJVMが死ぬ。接続後に切断してもOOMEが必ず起こることです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/25 12:58

    それらしいバグ情報がありました。
    https://bugs.openjdk.java.net/browse/JDK-8213198
    今夜、じっくり読みます。

    キャンセル

  • 2019/09/26 10:22

    情報連携ありがとうございます。
    メソッドのバグである場合、今回作成したプログラムは極めて単純なものなので改修の目処もつきますが、これが商用の複雑なロジックであった場合に、ライブラリを含めひとつひとつ精査しなくてはいけないのでしょうか。。

    キャンセル

  • 2019/09/26 13:00

    バグの件は取り下げます。Coretto 8 の動作は確認しました。
    私の回答をあてにせず、swordoneさんの回答、コマンド行フラグ-XX:-UseGCOverheadLimitを試して結果を追記してください。

    キャンセル

-3

JAVAではガーベージコレクション(GCと略されることが多いです)という機能があって、未使用なメモリ領域は自動的に開放されるようになってます。
このため、メモリ不足で落ちるようなことは殆どない、と思っておけばよろしいかと思います

ただ、無節制に使用中のメモリ領域を確保し続けるなどした場合はその限りではないでしょうね

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/21 17:01

    jconsoleから確認したところYGC,FGCともに動いているようですが、FGC後にOLD領域が多少残った状態になり、その繰り返しによってOLD領域が蓄積されてOOMEが発生しているようです。

    今回のようなログ出力のみの処理であれば解放できないオブジェクトなどはないと思っていたのですが…

    キャンセル

  • 2019/09/21 21:39

    ないはずです。
    それはなにかおかしいかと。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる
  • トップ
  • Javaに関する質問
  • Javaで実装したプログラムを稼働させ続けた場合、いつかはOutOfMemoryが発生するのでしょうか?