Trouble 12: JNIに関する問題
<Q12-1>PIPEを使用してプロセスの起動確認/排他起動を行うCのプログラムを、JNIを使用して複数スレッドからCallすると、通常は一つしか起動されないCのプログラムが複数起動してしまいます。
| <発生環境> |
| OS |
Solaris2.6 |
| JDK |
JRE1.3 |
| Vender |
Sun |
- <A12-1>
- JNIを使用するラッピング用クラスのメソッドをCallするクラスを新たに作成し、ラッピング用クラスを更にラッピングする形で、各メソッドを非staticかつsynchronizedに設定することで解決できます。
上記のクラスのインスタンスをmainスレッド上でstaticに生成し、各スレッドがこのstaticに生成されたクラスのメソッドを介してJNIにアクセスしてください。
<Q12-2>JNIを使用しているプログラムでVMがcoreダンプしてしまいます。
| <発生環境> |
| OS |
Solaris |
| JDK |
JDK1.3.0 |
| Vender |
Sun |
- <A12-2>
- 以下の原因が考えられます。
- CのプログラムとのI/Fでおかしな値が渡されている。
- Cのプログラム中にメモリを確保(malloc)して開放(free)せずにプログラム終了した状態でガベージコレクションが動作した。
- Cのプログラムでバグが発生している。
- の場合、Cプログラムで処理前に値の検査をおこなうことで回避できます。
- の場合、JNIを使用している個所にSystem.gc()を入れることで場所を特定することができます。場所を特定し、freeをするようにCプログラムを修正する必要があります。
- の場合、Cプログラムのバグを修正する必要があります。
ネイティブコード内部でメモリリークが発生していると、JavaVMがガベージコレクションを実行したときに、異常終了する恐れがあります。
ネイティブコード実行タイミングとガベージコレクション実行タイミングにはズレが生じるため、問題箇所の発見が困難となります。 意図的にSystem.gc()を利用することで、メモリリーク発生箇所の発見を手助けすることができます。
<Q12-3>JavaからJNIを使用して呼び出した関数でvfork()を呼び出している場合、プロセスが停止することがあります。
| <発生環境> |
| OS |
Solaris2.6 |
| JDK |
JRE1.3 |
| Vender |
Sun |
- <A12-3>
- Solaris2.6ではマルチスレッドプロセスからvfork()を呼び出すとプロセスが破壊されることがあります。JavaVM自体がマルチスレッドで動作するので、JavaからJNIを使用して呼び出した関数でvfork()を呼び出している場合、プロセスが終了することがあります。trussを使用してvfork()を呼び出していないか調べてください。
<Q12-4>CのシグナルハンドラからJavaメソッドを呼ぶとVMがcoreダンプしてしまいます。
【発生条件】
- Cの関数でシグナルハンドラを記述する&Javaのメソッドをコールバックできるように、Javaのオブジェクトを記憶しておく。
- Javaのコードでは、シグナル待ちの状態でwaitしている。
- JavaVMに対して、シグナルを送る。
- Cのシグナルハンドラから、Javaのメソッドを呼び出す。*1
- 呼ばれたメソッドで、notifyする。
- Java側でその他の処理をする。
*1でJavaのメソッドを呼び出すと、呼び出したJavaメソッド内の処理で、JavaVMがcoreダンプする。
| <発生環境> |
| OS |
Solaris2.8 |
| JDK |
JDK1.3.0 |
| Vender |
Sun |
- <A12-4>
- 原因は不明ですが、以下の2点を変更することによる回避実績があります。
- Cのシグナルハンドラから呼び出される、Javaのメソッドをsynchronizedにするのではなく、JNIを使ってCのシグナルハンドラでsynchronizedブロックを実行する。
- Javaコードでnotify()を実行するのではなく、Cの関数でnotifyするようにする。
注意:本文書の内容に誤りがあり、またこの文書によって不利益を被っても、
Acroquest Technology 株式会社は一切関知いたしません。