关于此的信息很少,例如2006年的this和people放弃了优雅地释放JNI资源。
JNI_OnUnload
(Oracle doc)用于在JVM中不再需要本机功能时释放资源(特别是“全局引用”)。这样会加载本机库
static {
System.loadLibrary("mylibjni"); // on Linux this translates to "libmylibjni.so"
}
...但是Java没有提供明确的卸载方法。
发生了什么:在我的lib中,由于没有机会进行清理,该lib最终确实卸载了(我不知道何时,请参阅下面的调用堆栈),但为时已晚,这会触发某些拥有JNI global refs 的全局变量来调用DeleteGlobalRef
失败:
# JRE version: OpenJDK Runtime Environment (10.0.2+13) (build 10.0.2+13)
# Java VM: OpenJDK 64-Bit Server VM (10.0.2+13, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# C [libblahjni.so+0x9a7e6] JNIEnv_::DeleteGlobalRef(_jobject*)+0x14
深入其中,这是因为在进行卸载的线程上没有JNIEnv
(我在thread_local
的基础上缓存env)。当时尝试检索Env无效-我尝试使用JavaVM::GetEnv
和JavaVM::AttachCurrentThread
,尽管附加工作正常,但JavaVM::GetEnv
仍返回JNI_EDETACHED (-2)
。因此,大概在JVM生命周期中太晚了,无法附加/拥有env。
我已经尝试过的其他方法-根据上述2006年的文章,在Java中,我尝试做System.runFinalizersOnExit(true)
时没有运气。即使我确实看到了终结器被调用(与不调用runFinalizers时相反,请参见下面的输出),JNI_OnUnload
仍然没有被调用。
Checked JNI functions are being used to validate JNI usage
[Dynamic-linking native method java.lang.Shutdown.runAllFinalizers ... JNI]
Checked JNI functions are being used to validate JNI usage
[Dynamic-linking native method java.lang.Shutdown.halt0 ... JNI]
作为最后一条信息,lib卸载调用堆栈如下所示。我不知道它从哪里来。我在最新的Arch Linux,Java 10上运行,如果重要的话,我正在Docker中运行。我想从原则上对正常退出进行分类,因为这使您有信心轻松地发现项目生命周期中稍后出现的问题。
[Dynamic-linking native method java.lang.Shutdown.runAllFinalizers ... JNI]
Checked JNI functions are being used to validate JNI usage
[Dynamic-linking native method java.lang.Shutdown.halt0 ... JNI]
0# (some more code of my own ommitted at the top of the stack)
1# std::_Optional_payload<...
2# std::_Optional_base<...
3# std::optional<...>::~optional() in /orion/mpf-jni/Debug/libmylibjni.so
4# 0x00007FDCEC5E845C in /usr/lib/libc.so.6
5# 0x00007FDCEC5E858E in /usr/lib/libc.so.6
6# 0x00007FDCEB919B89 in /usr/lib/jvm/java-10-openjdk/lib/server/libjvm.so
7# 0x00007FDCEBDF58C6 in /usr/lib/jvm/java-10-openjdk/lib/server/libjvm.so
8# 0x00007FDCEBDF5346 in /usr/lib/jvm/java-10-openjdk/lib/server/libjvm.so
9# 0x00007FDCEBDF2770 in /usr/lib/jvm/java-10-openjdk/lib/server/libjvm.so
10# 0x00007FDCEBDF3D2F in /usr/lib/jvm/java-10-openjdk/lib/server/libjvm.so
11# 0x00007FDCEBDF3FBE in /usr/lib/jvm/java-10-openjdk/lib/server/libjvm.so
12# 0x00007FDCEBC0558A in /usr/lib/jvm/java-10-openjdk/lib/server/libjvm.so
13# 0x00007FDCEC378A9D in /usr/lib/libpthread.so.0
14# clone in /usr/lib/libc.so.6
1447612069173.971 Fatal| could not get JVM env object for JNI version [65540], error [-2]