【问题标题】:JNI_CreateJavaVM function method does not work and cannot be debuggedJNI_CreateJavaVM 函数方法不起作用,无法调试
【发布时间】:2019-06-21 10:46:06
【问题描述】:

JNI_CreateJavaVM 函数方法不起作用,无法调试。

  • 开发环境为win10 x64,jdk版本为1.8

  • Visual Studio 2017 社区版编写 C++ 项目


我正在学习 JNI。我正在尝试运行The Invocation API。以下网址为官网文档示例。
点击here

我构建了项目并添加了一个包含 jvm.lib 的项目依赖项。我将 jvm.dll 放在项目目录中。我成功运行了这个程序。

Main.test() 是打印hello world 的方法。但是程序在执行JNI_CreateJavaVM时退出,控制台显示返回值为1。

我无法调试,我不知道发生了什么。

#include <jni.h>


int main() {
    printf("begin..........\n");
    JavaVM *jvm;       /* denotes a Java VM */
    JNIEnv *env;       /* pointer to native method interface */
    JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1];
    char optionString[] = "-Djava.class.path =D:/Program Files/Java/jdk1.8.0_191/lib/";
    options[0].optionString = optionString;
    vm_args.version = JNI_VERSION_1_8;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface
     * pointer in env */

    int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    printf("result=%d", res);
    delete options;
    /* invoke the Main.test method using the JNI */
    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
    env->CallStaticVoidMethod(cls, mid, 100);
    /* We are done. */
    jvm->DestroyJavaVM();
    return 0;
}

我希望这个jvm可以被调用,但是当程序执行到`int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); 我哪里错了?为什么它不起作用?

退出截图 enter image description here

jvm.dll 位置 enter image description here

jvm.lib 链接器附加库目录 enter image description here

jvm.lib 链接器附加依赖项 enter image description here

【问题讨论】:

  • “不起作用”是什么意思?它整天坐在卧室里拒绝找工作?
  • 您是如何确定它在 JNI_CreateJavaVM 语句而不是 CallStaticVoidMethod 调用时崩溃的?您不能相信 printf,因为它不会在没有换行符的情况下将其缓冲区刷新到您的控制台。
  • 我在debug模式下运行项目,逐步调试程序,但是当程序执行到JNI_CreateJavaVM方法时,整个进程crash退出,后面的语句也没有执行。跨度>

标签: java c++ java-native-interface jnienv


【解决方案1】:

类路径

键和等号之间有一个空格。必须删除空格。

char optionString[] = "-Djava.class.path =D:/Program Files/Java/jdk1.8.0_191/lib/";

类路径值

java.class.path 值必须指向编译的 .class 文件所在的基目录。

看起来你没有使用包名,那么它是 Main.class 所在的目录,所以它应该看起来像这样:

char optionString[] = "-Djava.class.path=c:/Users/name/MyJavaPrograms/classes";

访问冲突

SEGV(或异常 0xC0000005)也在 JVM 启动时有意生成,以验证某些 CPU/OS 功能。

看到这个很好的答案:https://stackoverflow.com/a/36258856

在 Visual Studio 中,当显示异常对话框时,只需将其关闭即可。这将防止您在下次再次启动该程序时再次看到它。

Java

为了完整起见:Java 方法应该如下所示:

public class Main {

public static void test(int num) {
    System.out.println("Java: test called with '" + num + "'");
}

...

Visual Studio 配置

需要找到 jvm.dll。在 Visual Studio 中的 Configuration Properties/Debugging/Environment 添加 PATH=%PATH%;\bin\server

对于以后的部署,您可以考虑将整个 JRE 放入应用程序的子文件夹中,并使用相对路径引用它。

演示

最后是一个简短的演示(在此处添加了一个 \n printf("result=%d\n", res); 以单独一行):

【讨论】:

  • 首先,我删除了这个空间。第一次尝试将java.class.path指向jdk安装路径,还是停止运行。第二次,我将 java.class.path 指向 Main 类的编译目录,它停止运行。看来我的异常是0x001不是0xc00005,你的demo打不开,我做错了什么?
  • 我的依赖库和动态链接库是不是位置不对?还是我少加了一部分?我在问题中上传了我的环境信息,你可以看看
  • 您不应该只复制 Java 运行时的一小部分。如果您想在某个时间点部署应用程序,您可以将 JRE 放入应用程序的子文件夹中。
  • 在 Visual Studio 中的 Configuration Properties/Debugging/Environment 下添加 PATH=%PATH%;\bin\server。我已经更新了答案。
猜你喜欢
  • 1970-01-01
  • 2017-03-27
  • 2021-06-11
  • 2018-08-25
  • 2016-04-10
  • 2021-05-10
  • 2018-12-07
  • 1970-01-01
相关资源
最近更新 更多