我通过JNI创建了一个JVM,如下所示:
bool JavaVM_Create(Jvm* &ptr, int argc, const char* argv[])
{
bool result = false;
if (!ptr && argc > 0)
{
ptr = new Jvm();
JavaVMInitArgs jvm_args;
JavaVMOption* options = new JavaVMOption[argc];
for (int i = 0; i < argc; ++i)
{
options[i].optionString = const_cast<char*>(argv[i]);
}
JNI_GetDefaultJavaVMInitArgs(&jvm_args);
jvm_args.version = JNI_VERSION_1_8;
jvm_args.nOptions = 2;
jvm_args.options = options;
jvm_args.ignoreUnrecognized = false;
result = true;
jint num_vms = 0;
JavaVM* vms[5] = {0};
if (JNI_GetCreatedJavaVMs(vms, 5, &num_vms) == JNI_OK)
{
if (num_vms > 0)
{
ptr->vm = vms[0];
ptr->vm->AttachCurrentThread();
delete[] options;
return result;
}
}
if (!ptr->createJVM(&jvm_args))
{
result = false;
}
delete[] options;
}
return result;
}
void JavaVM_Free(Jvm* &ptr)
{
if (ptr && ptr->vm)
{
ptr->vm->DetachCurrentThread();
ptr->vm->DestroyJavaVM();
}
delete ptr;
ptr = nullptr;
}
我使用JNI_GetCreatedJavaVMs
的原因是为了修复它所声明的JDK中的错误:
jint DestroyJavaVM(JavaVM * vm);
卸载Java VM并回收其资源。支持 JDK / JRE 1.1中的DestroyJavaVM未完成。从JDK / JRE 1.1开始 主线程可以调用DestroyJavaVM。从JDK / JRE 1.2开始,任何线程, 无论是否附加,都可以调用此功能。如果是当前线程 附加,VM等待,直到当前线程是唯一的 非守护程序用户级Java线程。如果当前线程不是 附加,VM附加当前线程,然后等待直到 当前线程是唯一的非守护进程用户级线程。 JDK / JRE 仍然不支持VM卸载,但是。
因此,我无法“创造,摧毁,创造,摧毁,重复”。 相反,我必须为应用程序的生命周期创建,保持实例,并且只在我的应用程序即将关闭时销毁该实例。
这很糟糕,因为如果我想将两个不同的jar加载到JVM中,我就不能。它们可能有也可能没有同名的类。内存使用天空火箭。
因此,我试图找到一种方法来完全卸载JVM(销毁它)或卸载所有已加载的类(重置它)。
任何想法或解决方案?
答案 0 :(得分:1)
最简单的方法是启动一个新的进程,然后销毁完成的进程。
另一个解决方案是使用ClassLoader加载您想要稍后卸载的类。当卸载ClassLoader时,它的所有类都被释放。
BTW您可以同时加载多个ClassLoader,甚至可以加载相同类的不同版本。
恕我直言试图从JNI创建和销毁JVM是非常棘手的(尽管不像过去那样棘手),我只会这样做作为最后的手段。有许多方法可以实现您想要的更简单的方法。