LoginSignup
1
1

More than 5 years have passed since last update.

JFileChooserをインスタンス化すると、とあるDLLが正常動作しなくなった件

Last updated at Posted at 2014-12-19

はじめに

仕事でSwingを使う機会があったのですが、その時に一箇所ドハマリした所があったので、メモ的に残します。
問題を起こしていたのは、SwingのJFileChooserです。 今時、Swingを使う方はほとんどいないとは思いますが、同じ事象にあってしまった方限定で書いてみます。
ちなみに、解決策は自分では見つけられませんでした・・・。
良い方法があったら教えて下さい。

出会ってしまった事象

JFileChooserをインスタンス化したあとに、JNAでとあるDLLの関数を呼び出すとDLL内で必ずエラーが発生し正常動作しなくなる。

なんでこんなことが、、、?

情弱なので、憶測の域を出ないのですが恐らくこんなことが起こっていると思われます。

  • JFileChooserがインスタンス化すると、インスタンスがネイティブライブラリをロードしインスタンスが参照を外れてもGCで開放されず掴んで離さなくなる。
  • JNAで呼びだそうとしているDLLがそのライブラリを使用している。 なので、必要なライブラリ読み込みができずDLL内でこけて、エラーを返す。

だったら、JFileChooserの参照を消せばいけるのでは・・・!?

結論から言うと、上手くいきませんでした。
スニペットですが、以下の様なコードを動かすとします。

test.java
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は参照が外れたあともオブジェクトが生き続ける・・・?

というのを、試してみました。

gcTest.java
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で代替したら上手くいきました。。。
びっくりするほど、バッドプラクティスなので何とかしたいのですが・・・
改めて、もし良い方法をご存知の方がいたらアドバイスをお願いしたいです・・・

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1