JNI - есть ли способ заставить JNI_OnUnload вызываться JVM? - PullRequest
0 голосов
/ 29 ноября 2018

Существует очень мало информации об этом, например это с 2006 года, и человек отказались от изящного освобождения ресурсов JNI.

JNI_OnUnload ( Oracle doc ) предназначен для высвобождения ресурсов (в частности, «глобальных ссылок»), когда ваша внутренняя функциональность больше не нужна из JVM.Нативная библиотека будет загружена следующим образом

static {
    System.loadLibrary("mylibjni"); // on Linux this translates to "libmylibjni.so"
}

... но Java не предлагает явного способа выгрузки.

Что происходит : в моей библиотеке из-зане имея возможности выполнить очистку, библиотека в конечном итоге выгружается (я не понимаю, когда, см. ниже стек вызовов), но слишком поздно, это вызывает некоторые глобальные переменные, владеющие 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 в потоке, выполняющем выгрузку (я кеширую env на thread_local основе).Попытка получить 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]
...