你可以在使用JNI从java调用的c ++函数中创建一个新的JVM吗? [英] Can you create a new JVM in a c++ function called from java using JNI?

查看:405
本文介绍了你可以在使用JNI从java调用的c ++函数中创建一个新的JVM吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我的设置是我有一个由我开发的.dll( A.dll ),它在原始应用程序中从外部进程调用,该进程基本上只是一个.exe文件我没有( B.exe )的源代码。 A.dll 的目的是与.jar文件进行通信,该文件也是由我开发的( C.jar )。因此,在应用程序中,通信流程如下所示

So my setup is that I have a .dll which is developed by me (A.dll) which in the original application is called from an external process which is basically just a .exe file that I do not have the source code for (B.exe). The purpose of A.dll is to communicate with a .jar file, which is also developed by me (C.jar). So in the application, the "communication flows" as shown below

B.exe - > A.dll - > (通过JNI) - > C.jar

B.exe -> A.dll -> (through JNI) -> C.jar

现在,我要做的是添加在 C.jar 的开发环境中,作为我的测试套件的一部分,在 A.dll C.jar 之间进行的调用。到目前为止,我已经创建了另一个.dll( D.dll ),它反映了 A.dll 中的所有功能,但是使用了JNIEXPORT,只是直接调用到 A.dll 中的相应功能。所以这种情况下的沟通流程如下:

Now, what i want to do is to add the calls going between A.dll and C.jar as a part of my test suite in the development environment for C.jar. What I have so far is that I have created another .dll (D.dll) which mirrors all functions in A.dll, but with JNIEXPORT, and simply makes direct call to the respective function in A.dll. So the "communication flow" in this situation will be as follows:

C.jar开发框架中的单元测试 - >(通过JNI) - > D.dll - > A.dll - >(通过JNI) - > C.jar

Unit test in C.jar development framework -> (through JNI) -> D.dll -> A.dll -> (through JNI) -> C.jar

此时,一个非常简单的函数调用只是在 C.jar 中打印出来的东西在整个链中起作用;从单元测试电话一直到 C.jar 。但是当我在 A.dll 中调用函数时会出现问题,该函数使用 CreateJavaVM()创建一个新的JVM,这会产生以下错误:

At this point, a very simple function call that simply prints out something in C.jar works through the whole chain; all the way from the unit test call and into C.jar. The problem however arises when i call the function in A.dll which creates a new JVM using CreateJavaVM(), which produces the following error:

VM初始化期间发生错误
无法加载本机库:找不到指定的程序

Error occurred during initialization of VM Unable to load native library: The specified procedure could not be found

所以基本上我想知道它是否真的可以这样做,或者当已经有一个正在运行的JVM时,只是不可能调用 CreateJavaVM()在同一个过程中?我知道你不能在同一个进程中多次调用 CreateJavaVM(),但是在这种情况下它只被调用一次但是过程中已经存在JVM - 你甚至可以运行几个JVM在同一过程中?

So basically I'm wondering if it is actually possible to do this, or is it just simply impossible to call CreateJavaVM() when there is already a running JVM in the same process? I know that you can't call CreateJavaVM() several times within the same process, but in this situation it is only called once but a JVM already exists in the process - can you even have several JVMs running in the same process?

解决方案:

感谢@ apangin的回答下面的代码片段解决了我的问题:

Thanks to @apangin's answer the code snippet below solved my problem:

jsize nVMs = 0; 
JavaVM** buffer;

jni_GetCreatedJavaVMs = (GetCreatedJavaVMs) GetProcAddress(GetModuleHandle(
  TEXT("jvm.dll")), "JNI_GetCreatedJavaVMs");

if (jni_GetCreatedJavaVMs == NULL) {
  // stuff
  CreateJavaVM(&jvm, (void **) &env, &args);
} else {
  jni_GetCreatedJavaVMs(NULL, 0, &nVMs); // 1. just get the required array   length
  JavaVM** buffer = new JavaVM*[nVMs];
  jni_GetCreatedJavaVMs(buffer, nVMs, &nVMs); // 2. get the data
  buffer[0]->GetEnv((void **) &env, jni_version); // 3. get environment
  jvm = buffer[0];
}


推荐答案

当前的JNI规范明确指出 在一个虚拟机中创建多个虚拟机单个进程不受支持 ,这实际上是在 HotSpot源代码

Current JNI specification explicitly states that creation of multiple VMs in a single process is not supported, and this is actually asserted in HotSpot source code.

即使你的dll调用 JNI_CreateJavaVM 只有一次,这并不意味着这是整个过程中的第一次调用。实际上, JNI_CreateJavaVM 首先由 java.exe 或IDE的另一个启动程序调用( idea.exe eclipse.exe netbeans.exe 等)。

Even if your dll calls JNI_CreateJavaVM only once, it does not mean that this is the very first call within the whole process. In fact, JNI_CreateJavaVM is first called by java.exe or by another launcher of your IDE (idea.exe, eclipse.exe, netbeans.exe etc).

因此,不要盲目地创建Java VM, A.dll 应首先通过调用检查当前进程中JVM是否已存在 JNI_GetCreatedJavaVMs 。如果函数返回非空数组,则使用 GetEnv AttachCurrentThread 获取现有VM的 JNIEnv * ,否则创建一个新VM。

Therefore, instead of creating Java VM blindly, A.dll should check first if JVM already exists in current process by calling JNI_GetCreatedJavaVMs. If the function returns nonempty array, then use GetEnv or AttachCurrentThread to obtain JNIEnv* for the existing VM, otherwise create a new VM.

这篇关于你可以在使用JNI从java调用的c ++函数中创建一个新的JVM吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆