🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

Q&A

4回答

4407閲覧

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

dropttt

総合スコア4

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

0グッド

6クリップ

投稿2019/09/20 09:32

編集2019/09/26 06:45

お世話になります。

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

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

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

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

Java

1class main{ 2 public static void main(String[] args){ 3 try{ 4 while(true){ 5 System.out.println("testtest"); 6 Thread.sleep(1); 7 } 8 }catch(InterruptedException e){ 9 e.printStackTrace(); 10 } 11 } 12}

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

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"

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

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/21 19:03

swordone

総合スコア20669

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

q_sane_q

2019/09/23 01:16

横から失礼します 私も見ていて気になったので試してみました。 Eclipseのヒープ・ステータスを見ていたところ System.out.println("testtest") を String text = "testtest" に 変えたら動きがほとんどなくなったためprintlnかもしれないです。 printlnの中を掘って行ったらStringを入れ込むchar[]をnewしていたりするのでそういうのを掃除しているのかも…完全には追いきれていないので正しいところはわからないのですが。
dropttt

2019/09/24 01:00

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

2019/09/26 06:48 編集

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

0

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

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

投稿2019/09/21 10:57

pepperleaf

総合スコア6385

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/09/24 01:04

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

0

jconsole

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

Java

1Exception in thread "RMI TCP Connection(idle)" Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded 2java.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/22 12:28

編集2019/09/30 09:49
xebme

総合スコア1090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dropttt

2019/09/25 00:57

ご教示頂きありがとうございます。 確かにjconsoleを用いて結果を見ていたので、仰る通りです。 再度検証してみましたが、jconsoleの監視によるエラー(?)が再発しました。 そして、監視なしでも実行してみましたが、RMI TCP Connectionのエラーは表示されずにOOMEのエラーだけ表示され、結果としては落ちてしまいました..
xebme

2019/09/25 03:26

RMIですが、JVMがRMIサーバー、jconsoleがRMIクライアントになるので当然の結果です。jconsoleは疑いの対象からはずしましょう。System.outを疑うのですが、Coretto/Windowsの組み合わせも疑うことになりますね。 スリープが短いために起きているのか。一定時間で考えると、println()の出力量 > GCの量と推測。チューニングで解決できないか?スリープ時間を少しずつ長くしてjconsoleでGC状況を見るのはどうか。 本当の原因は?そもそも、Corettoは、JDKからどれだけ変更が加えられているのか?
dropttt

2019/09/26 01:22

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

2019/09/26 04:00

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

0

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

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

投稿2019/09/20 10:21

y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dropttt

2019/09/21 08:01

jconsoleから確認したところYGC,FGCともに動いているようですが、FGC後にOLD領域が多少残った状態になり、その繰り返しによってOLD領域が蓄積されてOOMEが発生しているようです。 今回のようなログ出力のみの処理であれば解放できないオブジェクトなどはないと思っていたのですが…
y_waiwai

2019/09/21 12:39

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問