JNIで、例外が起きたかどうかのみをチェックできる関数があった。
今までExceptionOccurred()を使ってたんだけど、これが返すオブジェクト(例外インスタンス)は、実はローカル参照を保持しているらしい。
つまり関数実行中はJNIのJavaVMは「使用中」と判断するわけ。
この判断情報を保持する領域も限られているから、どんどんExceptionOccurred()を使うと、無駄にリソースが使われてしまうということ。
で、普通のJavaのソースならローカル変数にnullを入れることによってローカル参照を終了させていたけど、C言語/C++ではローカル変数にNULLを代入したところで、JavaVMに分かるはずがない。
ちゅーわけで、DeleteLocalRef()という関数を呼ぶと ローカル参照を終了できるらしい。
まぁこれを呼ばなくても、JNIの呼び出しが終了すればローカル参照は全部解放してくれるらしいので、すぐ終わる関数ならそんなに気にする必要は無いでしょう。
ちなみに何故こんなことを調べていたかというと、自作のJNI関数がメモリリークしてたみたいだったので、オブジェクトがどう解放されるかを知りたかったから。
結果的にはローカル参照は関係なくて、Releaseの仕方が間違ってたんだけど。
↓要点だけ抜き出すと こんな感じ
jbyte* elems = env->GetByteArrayElements(arrj, NULL);
elems += 128;
env->ReleaseByteArrayElements(arrj, elems, JNI_ABORT);
これに気付いたときには、我ながら唖然としたね(呆)
取得したポインターをずらして、それを解放できるわけないじゃん!!!
解放動作がJNI_ABORTだったのでたまたま例外が発生したりはしなかったみたいだけど、当然メモリの解放は正常に行われず、正にメモリリークしていたわけ。
“昔の自分”ってヤツぁ、馬鹿だね(嘆)