JavaにC ++デストラクタ(JNI)を呼び出させる
-
06-07-2019 - |
質問
この質問は以前に聞かれたと思っていましたが、ここで見つけることができませんでした...
SWIGを使用して、C ++クラスのJNIラッパーを作成しました。 Javaはクラスのfinalize()を呼び出さないように見えることを除いて、すべて正常に動作します。したがって、クラスのデストラクタが呼び出されることはありません。クラスのデストラクタは最終的なファイルI / Oを行うため、残念ながら、これは単なるメモリリークではありません。
Googleを検索しても、JavaにGCを強制してオブジェクトを破壊する方法はないようです。本当ですか?
SWIGファイルを操作してC ++デストラクタを呼び出すJava関数を作成できることはわかっていますが、このクラスは複数の異なるプラットフォーム/言語のエンドユーザーによって使用されるため、Javaのみを追加すると矛盾が発生しますテクニカルライターが気に入らないこと。
解決
System.gc()でGCを強制することはできません。 また、たとえば、アプリが短時間しか実行されず、ファイナライザがまったく実行されない(終了時にJVMが実行しない)場合など、GCが実行されることは保証されません。 close()またはdestroy()またはクラスの関数を作成し、このクラスのインスタンスを使い終わったら、できればfinallyブロックから呼び出すようにしてください。
MyClass x = null;
try{
x = new MyClass();
x.work();
} finally {
if (x!=null)
x.close();
}
他のヒント
Javaファイナライザは、私の意見ではほとんど役に立たず、C ++デストラクタに代わるものではありません。残念ながら、JavaにはC ++ RAIIに代わるものはありません。
Javaのファイナライズを強制しようとしないでください。何でも完了したら、それを破棄するすべての関数です。できることはそれだけです。
特定の時間に finalize
メソッドのコードに依存している場合、アプローチを再検討する必要があります。ここでの問題は、オブジェクトがガベージコレクションされるタイミングがわからないため、 finalize
がJVMによっていつ呼び出されるかわからないことです。
クラスは他のプロジェクトで再利用されるため、エンドユーザーがクラスのインスタンスを収集されないように使用したり、クラスのインスタンスへの静的参照を作成するなど、ガベージコレクションはほとんどありません。 close
または destroy
メソッドを作成することが、Javaオブジェクトに関連付けられたC ++クラスのインスタンスが使用しているリソースが適切に解放されるようにするための最も安全な方法だと思います。
再利用が懸念されるため、C ++デストラクタでリソースが解放されたかどうかを確認し、解放されていない場合は同じコードを呼び出すことができます。
class MyThing {
public:
void close();
~MyThing();
private:
bool released = false;
};
void
MyThing::close() {
// close logic here
this->released = true;
}
MyThing::~MyThing() {
if (!released) {
this->close();
}
}
この方法により、既存のC ++コードを大幅に変更する必要がなくなり、JNIを介して実行されるネイティブコードのコンテキストでリソースが確定的にリリースされることを保証できます。
SWIGで作成されたコードをさらに調べてみると、SWIGの人々は実際にこれをすでに処理していることがわかります。delete()関数が追加されています。プログラマとGCの両方がオブジェクトを削除する可能性も十分に考慮されているようです。
このような問題は、C#が IDisposableを選択した理由です。 >確定的なファイナライズのパターン。
同じパターンに従って、Javaユーザーに合わせて調整することをお勧めします。
c ++クラスで、リソースを破棄する別個のパブリックメソッドを作成します。それを近くに呼び出すか、処分するか、何か。
C ++デストラクタでpublicメソッドを呼び出し、C ++クラスの管理/ GCユーザーに、メモリリークを回避するためにメソッドを呼び出す必要があることを伝えます。