このページで解決しない高度なJavaのシステム障害はJaTSにお任せください

Trouble 4: Javaプログラムが止まってしまいます

4-1
ObjectStreamを用いて、ファイルのReadWriteを行う際に、Write時に、1オブジェクト毎に同一ファイルのオープン・クローズを行うと、Readする際に2オブジェクト目以降が読込めません。
4-2
Windows98において、Runtime.exec()により起動したjavawプロセスがコンソール出力を行っていた場合、一定量の文字を出力後にプログラムの動作が停止してしまいます。(javaの場合は停止しない)
4-3
サウンドを連続して再生しているとアプリケーションが操作不能になりました。
4-4
プログラムが何も出力しないで止まってしまいます。
4-5
JNIを使用しているプログラムでVMがcoreダンプしてしまいます。
4-6
JavaからJNIを使用して呼び出した関数でvfork()を呼び出している場合、プロセスが停止することがあります。
4-7
CのシグナルハンドラからJavaメソッドを呼ぶとVMがcoreダンプしてしまいます。
4-8
リモートデバッグ中にLinux上の対象JavaVMが固まってしまいます。デバッグ対象VMがWindows上で動作している場合には起こりません。
4-9
Java2Dを使用したアプリケーションで、HotSpotエラーが発生してしまいます。
4-10
Stringのmatches()メソッドを呼び出すとハング(hang)してしまったようで、反応が返ってこなくなってしまいました。
4-11
System.getPropertyが再帰的に呼び出され、StackOverFlowになります。
4-12
特定のLinux上でプログラムを動かしているとHotSpot Virtual Machine Errorが発生します。
4-13
メモリを大量確保しないアプリケーションでOutOfMemoryErrorが発生します。
4-14
getStackTrace()を頻繁に実行するとOutOfMemoryErrorが発生します。
4-15
RMI通信でSSLの設定を行ったところ、Memoryが大量に消費され、アプリケーションが停止します。


<Q4-1>ObjectStreamを用いて、ファイルのReadWriteを行う際に、Write時に、1オブジェクト毎に同一ファイルのオープン・クローズを行うと、Readする際に2オブジェクト目以降が読込めません。

オブジェクト単位のログ出力を、バイナリ形式で行おうとしたところ、問題が発生しました。

<発生環境>
OS Solaris2.5.1
JDK JDK1.2.1
Vender Sun
<A4-1>
ファイルをクローズすると、バイナリの終端情報がファイルに付加されます。
そのため、その後更にオープン・クローズを繰り返しても、終端情報以降を利用することができません。
1ファイルに連続して書き込むのであれば、ファイルをオープンし続けるか、テキスト形式への変更が必要です。
Page Top

<Q4-2>Windows98において、Runtime.exec()により起動したjavawプロセスがコンソール出力を行っていた場合、一定量の文字を出力後にプログラムの動作が停止してしまいます。(javaの場合は停止しない)


<発生環境>
OS Windows
JDK JDK1.3.0
Vender Sun
<A4-2>
コンソールバッファが一杯になっているために起きている現象です。Runtime.exec()を使用したjavaプログラムにおいて、javawプロセスによるコンソール出力を読み込んでください。
もしくは、javawプロセスにおいて、コンソールの出力を行わないようにしてください。
Page Top

<Q4-3>サウンドを連続して再生しているとアプリケーションが操作不能になりました。

マシンが高負荷である状態で、サウンド鳴動が停止せずアプリケーションが操作不能になりました。アプリケーションを再起動すると回復します。

<発生環境>
OS Windows NT/2000/XP
JDK JDK1.3
Vender Sun
<A4-3>
サウンドを鳴らしているスレッドとJavaSoundのイベントディスパッチスレッド (JavaSound EventDispatcher)がデッドロックしている可能性があります。
サウンドを鳴らしているスレッドを常に監視し、サウンドファイルが終了した時点で明示的にサウンドの再生を終了させるようにしてください。
この対処で、JavaSound EventDispatcherスレッドがデッドロックすることを回避できます。(サウンドファイルの終了はClipインタフェースのisRunning()メソッドで確認できます)
Page Top

<Q4-4>プログラムが何も出力しないで止まってしまいます。

私のプログラムが止まっている様です。コンソールにもログファイルにも何も出力しないため、何が起こっているかわかりません。
解析方法を教えてください。

<発生環境>
OS Any
JDK JDK1.2以降
Vender Sun
<A4-4>
デッドロックが発生している可能性が高いです。まずスレッドダンプを取得しましょう。

スレッドダンプを取得する方法は次の通りです。

○Windowsの場合:
  java.exeが動作しているDOS窓上で、Ctrl+Breakを押します。
  (javaw.exeでは取得できません)

○UNIX系OSの場合:
  対象のJavaプロセスにQUITシグナルを送信します。
  $ kill -QUIT <pid>

この操作により、スレッドダンプがJavaVMの標準エラー出力に表示されます。

J2SE1.4.1からは HotSpotVMにデッドロック検出ユーティリティが追加され、モニターオブジェクトをロックし合うような単純デッドロックの場合、スレッドダンプと共にJavaVMが警告を発してくれます。また複雑なデッドロックやライブロックが発生している場合でも、スレッドダンプを解析することでロック箇所を特定することができるでしょう。

以下はJ2SE1.4.1_01-b01によるスレッドダンプの出力例です。

Full thread dump Java HotSpot(TM) Client VM (1.4.1_01-b01 mixed mode):

"DestroyJavaVM" prio=5 tid=0x00034788 nid=0x764 waiting on condition [0..7fadc]

"Thread-2" prio=5 tid=0x00A12430 nid=0xaf4 waiting for monitor entry [acef000..acefd8c]
        at sample.deadlock.DeadLock.lock(DeadLock.java:29)
        - waiting to lock <02AA3B28> (a java.lang.Object)
        at sample.deadlock.DeadLock.run(DeadLock.java:47)
        - locked <02AA3B30> (a java.lang.Object)

"Thread-1" prio=5 tid=0x00A12EB0 nid=0x5cc waiting for monitor entry [acaf000..acafd8c]
        at sample.deadlock.DeadLock.lock(DeadLock.java:29)
        - waiting to lock <02AA3B30> (a java.lang.Object)
        at sample.deadlock.DeadLock.run(DeadLock.java:47)
        - locked <02AA3B28> (a java.lang.Object)

==== 中略 ====

"Suspend Checker Thread" prio=10 tid=0x009A8530 nid=0xb08 runnable

Found one Java-level deadlock:
=============================
"Thread-2":
  waiting to lock monitor 0x9a4b7c (object 0x2aa3b28, a java.lang.Object),
  which is held by "Thread-1"
"Thread-1":
  waiting to lock monitor 0x9a4b5c (object 0x2aa3b30, a java.lang.Object),
  which is held by "Thread-2"

Java stack information for the threads listed above: 
=================================
"Thread-2":
        at sample.deadlock.DeadLock.lock(DeadLock.java:29)
        - waiting to lock <02AA3B28> (a java.lang.Object)
        at sample.deadlock.DeadLock.run(DeadLock.java:47)
        - locked <02AA3B30> (a java.lang.Object)
"Thread-1":
        at sample.deadlock.DeadLock.lock(DeadLock.java:29)
        - waiting to lock <02AA3B30> (a java.lang.Object)
        at sample.deadlock.DeadLock.run(DeadLock.java:47)
        - locked <02AA3B28> (a java.lang.Object)

Found 1 deadlock.
上の例では、"Thread-1"と"Thread-2"がlock()メソッドでロックしており、そのデッドロックをJavaVMが検出/指摘していることが分かります。

参考)
自分のプログラムでスレッドを生成するときには、名前をつけることをお勧めします。
スレッド名称はデフォルトでは「Thread-<連番>」となり、スレッドダンプの解析が非常に困難になります。
Page Top

<Q4-5>JNIを使用しているプログラムでVMがcoreダンプしてしまいます。


<発生環境>
OS Solaris
JDK JDK1.3.0
Vender Sun
<A4-5>
以下の原因が考えられます。
  1. CのプログラムとのI/Fでおかしな値が渡されている。
  2. Cのプログラム中にメモリを確保(malloc)して開放(free)せずにプログラム終了した状態でガベージコレクションが動作した。
  3. Cのプログラムでバグが発生している。
  1. の場合、Cプログラムで処理前に値の検査をおこなうことで回避できます。
  2. の場合、JNIを使用している個所にSystem.gc()を入れることで場所を特定することができます。場所を特定し、freeをするようにCプログラムを修正する必要があります。
  3. の場合、Cプログラムのバグを修正する必要があります。
ネイティブコード内部でメモリリークが発生していると、JavaVMがガベージコレクションを実行したときに、異常終了する恐れがあります。 ネイティブコード実行タイミングとガベージコレクション実行タイミングにはズレが生じるため、問題箇所の発見が困難となります。 意図的にSystem.gc()を利用することで、メモリリーク発生箇所の発見を手助けすることができます。
Page Top

<Q4-6>JavaからJNIを使用して呼び出した関数でvfork()を呼び出している場合、プロセスが停止することがあります。


<発生環境>
OS Solaris2.6
JDK JRE1.3
Vender Sun
<A4-6>
Solaris2.6ではマルチスレッドプロセスからvfork()を呼び出すとプロセスが破壊されることがあります。JavaVM自体がマルチスレッドで動作するので、JavaからJNIを使用して呼び出した関数でvfork()を呼び出している場合、プロセスが終了することがあります。trussを使用してvfork()を呼び出していないか調べてください。
Page Top

<Q4-7>CのシグナルハンドラからJavaメソッドを呼ぶとVMがcoreダンプしてしまいます。

【発生条件】

  1. Cの関数でシグナルハンドラを記述する&Javaのメソッドをコールバックできるように、Javaのオブジェクトを記憶しておく。
  2. Javaのコードでは、シグナル待ちの状態でwaitしている。
  3. JavaVMに対して、シグナルを送る。
  4. Cのシグナルハンドラから、Javaのメソッドを呼び出す。*1
  5. 呼ばれたメソッドで、notifyする。
  6. Java側でその他の処理をする。
*1でJavaのメソッドを呼び出すと、呼び出したJavaメソッド内の処理で、JavaVMがcoreダンプする。

<発生環境>
OS Solaris2.8
JDK JDK1.3.0
Vender Sun
<A4-7>
原因は不明ですが、以下の2点を変更することによる回避実績があります。
  1. Cのシグナルハンドラから呼び出される、Javaのメソッドをsynchronizedにするのではなく、JNIを使ってCのシグナルハンドラでsynchronizedブロックを実行する。
  2. Javaコードでnotify()を実行するのではなく、Cの関数でnotifyするようにする。

Page Top

<Q4-8>リモートデバッグ中にLinux上の対象JavaVMが固まってしまいます。デバッグ対象VMがWindows上で動作している場合には起こりません。


<発生環境>
OS デバッグ対象:RedHatLinux6.2 SMP
JDK JDK1.3
Vender Sun/IBM
<A4-8>
JavaVMのバグと思われます。 JDK1.3.1+1CPU用のカーネルではこの現象が発生しなくなっていますが、JDK1.3.1+SMPでは依然として発生しています。
Page Top

<Q4-9>Java2Dを使用したアプリケーションで、HotSpotエラーが発生してしまいます。

Java2Dを使用したアプリケーションを作成していますが、
実行中、コンソールに以下のメッセージが表示されて、終了してしまいます。

#  EXCEPTION_ACCESS_VIOLATION (0xcFF00005) at pc=0x6d1c5c68, pid=2608, tid=2140
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0-b64 mixed mode, sharing)
# Problematic frame:
# C  [dcpr.dll+0x5c68]
#
# An error report file with more information is saved as hs_err_pid2608.log

<発生環境>
OS Windows XP SP2
JDK 5.0 Update4
Vender Sun
<A4-9>
アンチエイリアスを有効にしていると、問題の現象と同じエラーが発生することがあります。
これは、JavaVMのバグですが、まだ修正されていません。
以下は、具体的な再現コード例です。

BufferedImage im = new BufferedImage(640, 480,
                                      BufferedImage.TYPE_INT_RGB);
 Graphics2D g2d = im.createGraphics();
 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                      RenderingHints.VALUE_ANTIALIAS_ON);
 GeneralPath path = new GeneralPath();
 path.moveTo(0, 0);
 path.lineTo(634, 57);
 path.lineTo(640, 65);
 path.closePath();
 g2d.draw(path);
現状、根本的な解決方法はありません。
Page Top

<Q4-10>Stringのmatches()メソッドを呼び出すとハング(hang)してしまったようで、反応が返ってこなくなってしまいました。

以下のような単純な処理です。

string.matches("(.*\n*)*")

<発生環境>
JDK 1.5.0_05
<A4-10>
String#matchesメソッドに改行(\n)を利用するとハングしてしまう(処理が進まなくなる)のは、Java Bug Databaseにも載っている、Javaのバグです。

参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6328855

回避策としては、改行(\n)をそのまま利用せずに、復帰改行(\r\n)を使えば良いようです。

例)
string.matches("(.*\r*\n*)*"));

他の回避策はない模様です。

また、Java Bug Databaseに修正の報告はあがっていませんので、改行(\n)を使う必要がある場合は、バージョンアップを待つしかないようです。
(2007/2/28現在)
Page Top

<Q4-11>System.getPropertyが再帰的に呼び出され、StackOverFlowになります。

以下のように、Propertyを繰り返し生成し、getPropertyで存在しないキーを指定すると、StackOverFlowが発生する可能性があります。

for(int num=0; num > 10000&; num++)
{
  Properties p = new Properties(System.getProperties());  ・・・①
  Properties System.setProperties(p);                     ・・・②
}

System.getProperty("test");

<発生環境>
JDK 1.5.0_12
<A4-11>
上記の①、②のコードを1回実行するたびに、getPropertyで再帰的に呼ばれる回数が
1回増えます。
そのため、①、②を繰り返し実行し、getPropertyで存在しないキーを指定して、
getPropertyを呼び出すと、プロパティの呼び出しが多数行われる状態になってしまいます。
これにより、CPU使用率も高くなってしまい、最終的にはStackOverFlowします。

参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4906193


回避策としては、①、②を以下のように書き換えます。

new Properties()せず、直接操作するようにすることで、
この問題の発生を防ぐことができます。

Properties p = System.getProperties();
System.setProperties(p);
参考)

以下は、問題発生時のスタックトレースの出力例です。
Exception in thread "main" java.lang.StackOverflowError
  at java.util.Hashtable.get(Hashtable.java:334)
  at java.util.Properties.getProperty(Properties.java:932)
  at java.util.Properties.getProperty(Properties.java:934)
  at java.util.Properties.getProperty(Properties.java:934)
  at java.util.Properties.getProperty(Properties.java:934)
  at java.util.Properties.getProperty(Properties.java:934)
  at java.util.Properties.getProperty(Properties.java:934)
  at java.util.Properties.getProperty(Properties.java:934)
  at java.util.Properties.getProperty(Properties.java:934)
  ==== 以下省略 ====

Page Top

<Q4-12>特定のLinux上でプログラムを動かしているとHotSpot Virtual Machine Errorが発生します。

WindowsやLinux上で通常動作しているネットワークプログラムを特定のLinuxで動作させると しばらくするとHotSpot Virtual Machine Errorが発生することがあります。

<発生環境>
OS Redhat Enterprise Linux 4
JDK JDK 1.5.0
<A4-12>
Java VMが利用しているLinuxのC言語ライブラリ(glibc)が提供する関数に
マルチスレッドのバグがあるために発生します。

参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6369541
http://sourceware.org/bugzilla/show_bug.cgi?id=2571

このバグは既に報告され修正されていますので、
glibcをアップデートすることで回避することが可能です。
Linuxの各ディストリビューションのアップデートを実施してください。

Redhat Enterprise Linux 4であればUpdate4で問題を解決したglibcにアップデートできます。
Page Top

<Q4-13>メモリを大量確保しないアプリケーションでOutOfMemoryErrorが発生します。

複数のWebアプリケーションをtomcat上で動かしています。
メモリを大量確保していないアプリケーションばかりなのですが、
長時間運用しているとOutOfMemoryErrorが発生してしまい、
tomcatが異常終了してしまいます。

表示されるエラーメッセージは以下の通りです。

Exception in thread "xxxx" java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)

<発生環境>
OS Any
JDK Any
<A4-13>
この現象はJava VMのPermanent領域が大量に必要になる場合に発生します。

Java VMが管理するメモリ領域にはヒープと非ヒープの2種類があります。

  1. ヒープ
    newなどを使って生成されるオブジェクトが利用する領域です。

  2. 非ヒープ
    ヒープ以外に、Javaの実行で必要になる領域です。各スレッドごとの
    スタック領域やJavaのクラス情報の格納領域などがあります。
Permanent領域は、非ヒープの一部であり、
主にJavaのクラス情報を保存するために使われます。

単純なプログラムでは、起動時に必要なクラス情報を読み込むため、
Permanent領域に新たに情報が追加されることはありません。

しかし、tomcatなどのような、起動した後に外部のjarファイルを読み込んで
実行する仕組みをもったプログラムの場合には、起動した後にも
Permanent領域への情報追加が行われる場合があります。

この情報追加が大量に行われるプログラムの場合には、
デフォルトで決められたPermanent領域が枯渇してしまいます。

Permanent領域が枯渇すると、ヒープが枯渇した場合と同じように、
OutOfMemoryErrorが発生して、プログラムが強制終了してしまいます。

[対策]
Permanent領域のサイズを指定するには-XX:MaxPermSizeオプションを利用します。
-Xmxオプションはヒープのメモリサイズを設定するオプションですので、
Permanent領域のサイズとは別になることにご注意ください。


 この記事の詳細な情報をJTSメールマガジンにて配信しています。
 情報を取得したい方は、メールマガジンのバックナンバーを参照して下さい。

Page Top

<Q4-14>getStackTrace()を頻繁に実行するとOutOfMemoryErrorが発生します。

正常動作していたアプリケーションを処理解析用に修正し、
定期的にスタックトレースを表示するようにしました。

その結果、長時間運用中にOutOfMemoryErrorが発生して、
アプリケーションが強制終了してしまいました。

表示されるエラーメッセージは以下の通りです。

Exception java.lang.OutOfMemoryError: requested 128 bytes for GrET* in
/BUILD_AREA/jdk1.5.0_14/hotspot/src/share/vm/utilities/growableArray.
cpp. Out of swap space?

<発生環境>
OS Any
JDK JDK 5.0
<A4-14>
この現象は、Java標準APIのjava.lang.Thread.getStackTrace()を
頻繁に呼び出した際に発生します。

JDK5.0のjava.lang.Thread.getStackTrace()の実装には、
C言語のソースコードレベルにおいてメモリ解放忘れのバグが存在します。
このバグが原因となり、java.lang.Thread.getStackTrace()を呼び出すたびに、
Cヒープと呼ばれるメモリ領域でメモリリークが発生します。

同様のメモリリークは、java.lang.Thread.getStackTrace()と同じC言語 のソースを利用している以下のJava APIでも発生します。
  • java.lang.Thread.getAllStackTraces()
  • java.lang.management.ThreadMXBean.getThreadInfo()
この件については以下のJavaのbugdatabaseで報告されています。

参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469701
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6434648


この問題はJDK6.0では修正されています。

そのためJDK5.0を利用したアプリケーションの場合には、
JDK6.0へ以降するか、以下の3つのメソッドの利用を避ける必要があります。

  1. java.lang.Thread.getStackTrace()
  2. java.lang.Thread.getAllStackTraces()
  3. java.lang.management.ThreadMXBean.getThreadInfo()

このうち1のjava.lang.Thread.getStackTrace()については、
java.lang.Throwable.getStackTrace()を使うことで回避することができます。

しかし2, 3についてはJDK5.0で現在回避する方法はありません。

JDK6.0への移行をお勧めします。


 この記事の詳細な情報をJTSメールマガジンにて配信しています。
 情報を取得したい方は、メールマガジンのバックナンバーを参照して下さい。

Page Top

<Q4-15>RMI通信でSSLの設定を行ったところ、Memoryが大量に消費され、アプリケーションが停止します。

RMI通信を行っているアプリケーションに対して、
RMIServerSocketFactoryとRMIClientSocketFactoryをオーバライドしたクラスを作成し、
SSL通信を行えるようにしたところ、
Memoryが大量に消費され、アプリケーションが停止します。

<発生環境>
OS Any
JDK JDK5.0以降
Vender Sun
<A4-15>
SSL通信用に作成した、RMIClientSocketFactoryの
equalsメソッドとhashCodeメソッドに問題がある可能性があります。

RMI通信では、クライアントからの通信時に、
サーバからクライアントにSocketFactoryをコピーします。

その際、同一のClientSocketFactoryが既にクライアントにある場合は、
コピー処理を行わず、そのClientSocketFactoryを通信に使用します。

ClientSocketFactoryの同一性は、equals、hashCodeメソッドで判定するため、
これらのメソッドが定義されていないと、毎回別のオブジェクトと見なされ、
通信の度に新しいClientSocketFactoryが生成されます。

さらに、ClientSocketFactoryに1対1でRenewCleanというスレッドが作成されるため、
通信の度にRenewCleanスレッドが作成され、使用メモリも増え続けてしまいます。

この問題は、Java Bug Databaseにも記載されています。


参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5053529

[対策]
RMIClientSocketFactoryのhashCodeメソッドとequalsメソッドを実装してください。
※このことは、RMIClienctSocketFactoryのJavaDocにも記述されています。

同様に、RMIServerSocketFactoryのJavaDocでも、
hashCodeメソッドとequalsメソッドを実装することが勧められているため、
実装が必要です。

hashCodeメソッドとequlasメソッドの例を以下に記載します。
public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + port;
  return result;
}

public boolean equals(Object obj) {
  if (this == obj)
    return true;
  if (obj == null)
    return false;
  if (getClass() != obj.getClass())
    return false;
  final SampleServerSocketFactory other = 
                   (SampleServerSocketFactory) obj;
  if (port != other.port)
    return false;
  return true;
}

Page Top

注意:本文書の内容に誤りがあり、またこの文書によって不利益を被っても、
Acroquest Technology 株式会社は一切関知いたしません。

  • 現象別Index
  • 原因別Index

Find Bugsバグ詳細

Find Bugs Bug Descriptions日本語版

RSSで更新情報を取得する

RSSとは、ホームページの更新情報を配信する為のフォーマットです。
RSSを利用すると、登録したページの情報が更新された場合に、更新情報を自動的に受け取る事ができます。

詳細

弊社小森が執筆致しました

Javaでオブジェクト指向開発

Javaプログラミング言語習得において、新人プログラマーの最初の障害は「オブジェクト指向の壁」です。
本書は、Javaのソフトウェア開発を中心に事業を発展させてきたAcroquest社の新人教育セミナーを加筆・書籍化したもので、大卒の新人に対して、ゼロからJava言語を教えてきた実績をフィードバックしています。

メールマガジン配信中

Javaトラブルシューティングのメルマガをはじめました!是非ご購読ください

詳細