はじめに
仕事でSwingを使う機会があったのですが、その時に一箇所ドハマリした所があったので、メモ的に残します。
問題を起こしていたのは、SwingのJFileChooserです。 今時、Swingを使う方はほとんどいないとは思いますが、同じ事象にあってしまった方限定で書いてみます。
ちなみに、解決策は自分では見つけられませんでした・・・。
良い方法があったら教えて下さい。
出会ってしまった事象
JFileChooserをインスタンス化したあとに、JNAでとあるDLLの関数を呼び出すとDLL内で必ずエラーが発生し正常動作しなくなる。
なんでこんなことが、、、?
情弱なので、憶測の域を出ないのですが恐らくこんなことが起こっていると思われます。
- JFileChooserがインスタンス化すると、インスタンスがネイティブライブラリをロードしインスタンスが参照を外れてもGCで開放されず掴んで離さなくなる。
- JNAで呼びだそうとしているDLLがそのライブラリを使用している。 なので、必要なライブラリ読み込みができずDLL内でこけて、エラーを返す。
だったら、JFileChooserの参照を消せばいけるのでは・・・!?
結論から言うと、上手くいきませんでした。
スニペットですが、以下の様なコードを動かすとします。
public static void main (String[] args) {
int retVal;
// JNAでDLLを呼び出します。
retVal = callDllFunc();
if(retVal == 0) {
// 呼び出したDLLが正常動作している場合
System.out.println ("DLL work properly")
} else {
// 呼び出したDLLが異常動作した場合
System.out.println ("DLL doesn't work properly")
}
// JFileChooserをインスタンス化します
JFileChooser fc = new JFileChooser();
// 参照を外します
fc = null;
// JFileChooserの参照が外れている状態で、DLLを呼びだします。
retVal = callDllFunc();
if(retVal == 0) {
System.out.println ("DLL work properly")
} else {
System.out.println ("DLL doesn't work properly")
}
}
/**
* 戻り値が0なら正常、1なら異常とします。
*/
private int callDllFunc() {
int retVal = Dll.INSTANCE.hogeProcess();
}
/**
* JNA用のインターフェースです。
*/
private interface Dll extended Library {
Dll INSTANCE = (Dll)Native.loadLibrary("C:¥hoge.dll", Dll.class);
int hogeProcess();
}
ここで、以下のように標準出力に出力されることを期待していたのですが、、、
DLL work properly
DLL work properly
結果は、
DLL work properly
DLL doesn't work properly
となってしまいます。
JFileChooserは参照が外れたあともオブジェクトが生き続ける・・・?
というのを、試してみました。
public void gcTest() {
// JFileChooserをインスタンス化します。
JFileChooser fc = new JFileChooser();
// 弱参照を作ります。
WeakReference<JFileChooser> wf = new WeakReference<JFileChooser> (fc);
// オブジェクトの参照を外します。
fc = null;
// GCしてみます。
Runtime.getRuntime().gc();
// オブジェクトの生死を確認します。
if (wf.get() != null) {
System.out.println("生きています");
} else {
System.out.println("もういません・・・");
}
}
gcTestを試しに1000回ループで回してみましたが、ただの一度もオブジェクトがGCで回収されることがありませんでした・・・。
もしかして・・・
JFileChooserが一度でも描画されると、以降GC対象にならないというバグが昔ありました。
Bug ID:JDK-4255413
これ、、、なおっているのでしょうか・・・?
試しに動かした感じは、直っていないような挙動をしていますが・・・
で、結局どうしたかというと・・・
JFileChooserの使用は諦めて、AWTのFileDialogで代替したら上手くいきました。。。
びっくりするほど、バッドプラクティスなので何とかしたいのですが・・・
改めて、もし良い方法をご存知の方がいたらアドバイスをお願いしたいです・・・