OpenJ9中调用DestroyJavaVM()失败的问题求助
C/C++嵌入JVM时
DestroyJavaVM()调用失败导致无法重启虚拟机 问题描述
在Windows环境下通过JNI在C/C++程序中嵌入JVM时,虚拟机初始化、启动流程均正常,但调用DestroyJavaVM()关闭虚拟机时返回-1错误,导致后续无法正常连续启动JVM。目前怀疑该问题是OpenJ9虚拟机特有的,正在测试其他JVM(如HotSpot)进行验证。
可复现代码
以下是基于Catch1.x编写的最小复现示例,仅依赖JNI头文件,配置正确JAVA_HOME后即可在Windows环境编译运行:
#define CATCH_CONFIG_MAIN #include "catch.hpp" #pragma once #pragma warning( push ) #pragma warning( suppress : 26451 ) #pragma warning( suppress : 26495 ) #pragma warning( suppress : 26812 ) #include <jni.h> #pragma warning( pop ) using create_java_vm_t = jint(JNICALL*)(JavaVM**, void**, void*); TEST_CASE("a minimum example for the internet", "[paljni]") { // 加载JVM函数 static create_java_vm_t create_java_vm = nullptr; if (!create_java_vm) { auto path = std::string(getenv("JAVA_HOME")) + "bin/default/jvm.dll"; auto dll = LoadLibrary(path.c_str()); REQUIRE(dll); create_java_vm = reinterpret_cast<create_java_vm_t>(GetProcAddress(dll, "JNI_CreateJavaVM")); REQUIRE(nullptr != create_java_vm); } // 初始化JVM启动参数 JavaVMInitArgs args = {}; args.version = JNI_VERSION_1_6; std::vector<JavaVMOption> options; options.emplace(options.end())->optionString = "-verbose:init"; // 输出初始化日志,显示线程似乎已正常关闭 args.options = options.data(); args.nOptions = options.size(); // 创建JVM JavaVM* jvm; JNIEnv* env; const auto create_ret = create_java_vm(&jvm, (void**)&env, &args); REQUIRE(JNI_OK == create_ret); // 销毁JVM - 此处返回-1,执行失败 const auto done = jvm->DestroyJavaVM(); REQUIRE(JNI_OK == done); FAIL("The test doesn't reach this point"); }
可能的原因与调试建议
- 线程调用限制:
DestroyJavaVM()必须在最初启动JVM的线程中调用,跨线程调用会直接返回失败。确保销毁操作和启动操作在同一个线程执行。 - JNI引用泄漏:未释放的全局引用、局部引用会阻止JVM销毁。调用
DestroyJavaVM()前,通过env->DeleteLocalRef()清理所有局部引用,检查全局引用是否全部通过env->DeleteGlobalRef()释放。 - OpenJ9特定逻辑:OpenJ9对JVM销毁的资源清理、线程终止逻辑与HotSpot存在差异,可能存在未完全终止的后台守护线程或残留资源。可切换到HotSpot测试对比,确认问题是否与虚拟机实现相关。
- 启用调试日志:打开
-verbose:jni、-Xcheck:jni:warn参数,查看JNI调用的详细日志,排查是否有非法引用或未处理的资源。
内容的提问来源于stack exchange,提问作者pal
相关产品推荐
相关产品推荐

