使用jni时出现致命错误

时间:2014-08-26 03:32:33

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

我试图使用jni从c ++调用java方法。实际上更多的回调(java - > c ++ - > java) 我通过在.exe(c ++ - > java)中测试它来检查c ++程序是否存在错误 该程序在视觉工作室中完美运行。但是当我将它转换为dll并在java中使用它时失败并崩溃。 我认为它与jvm.dll有关,因为我必须将它包含在我的visual studio项目中。

C ++:

#include <stdio.h>
#include <jni.h>
#include <string.h>
#include "Inter.h"

JNIEnv* create_vm(JavaVM ** jvm) {

    JNIEnv *env;
    JavaVMInitArgs vm_args;
    JavaVMOption options;
    options.optionString = "-Djava.class.path=C:\\Users\\SolidSnake\\workspace\\Test\\bin"; //Path to the java source code
    vm_args.version = JNI_VERSION_1_8;
    vm_args.nOptions = 1;
    vm_args.options = &options;
    vm_args.ignoreUnrecognized = 0;

    int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
    if(ret < 0)
        printf("\nUnable to Launch JVM\n");     
    return env;
}

void callMethod() {
    JNIEnv *env;
    JavaVM * jvm;
    env = create_vm(&jvm);
    jclass m;
    jmethodID test;
    m = env->FindClass("Main");
    test = env->GetStaticMethodID(m,"callbackFromC","()V");
    env->CallStaticVoidMethod(m,test);
}

的java:

public final class Main {

    public native int callToC();

    public static void callbackFromC() {
        System.out.println("Hello from C!");
    }

    public static void main(String[] args) {
        System.loadLibrary("Test");
        new Main().callToC();
    }

}

碰撞:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000007f9aed32ff8, pid=4016, tid=8228
#
# JRE version: Java(TM) SE Runtime Environment (8.0_11-b12) (build 1.8.0_11-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.11-b03 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [Test.dll+0x1a08]  JNIEnv_::FindClass+0x28
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows

这是程序如何进行的(j:callToC) - &gt; (c:callMethod) - &gt; (Y:callbackFromC)

1 个答案:

答案 0 :(得分:1)

我几天前遇到了同样的问题,我找到了问题的解决方案(可能不是最好的解决方案),现在我很自豪地分享它(这个可能对未来的某个人有用)。

当我只有两个项目(C ++ - &gt; Java),即C ++项目调用Java方法时,我的代码运行良好:

void JVM:: Init( const std:: string& javaClassesPath )  {    
    std:: string optionString = ( std:: string("-Djava.class.path=") + javaClassesPath );
    JavaVMOption options_;  
    options_.optionString = const_cast<char*>( optionString.c_str() );

    // initializing of JVM initial arguments:
    JavaVMInitArgs arguments_;
    memset( &arguments_, 0, sizeof( arguments_ ) );
    arguments_.version = JNI_VERSION_1_6;
    arguments_.nOptions = 1;
    arguments_.options = &options_;
    arguments_.ignoreUnrecognized = 0;

    // creating JVM:
    long status = JNI_CreateJavaVM( &jvm_, (void**)&env_, &arguments_ );    
    if ( status == JNI_ERR )        
        throw std:: exception("Error: unable to create Java Virtual Machine.\n");

    FindClass("ChartBuilder");
}

此代码的调用方式如下:

JVM JChartBuilder( "D:\\Java Src\\Chart\\Chart.jar" ); // the path that will be used as classpath when creating VM (unless this path is specified it will be unable to find the class ChartBuilder)

然后(Java-> C ++ Java) 当我得到第三个项目(Java)必须使用JNI从该C ++项目中调用方法时,我遇到了一个问题,即当一个已经在当前进程中运行时我无法创建VM。但我们可以附加到现有的VM!因此,可以更改上面列出的代码以满足此要求:

void JVM:: Init( const std:: string& javaClassesPath )
{
    // initializing of JVM options: 
    std:: string optionString = ( std:: string("-Djava.class.path=") + javaClassesPath );
    JavaVMOption options_;  
    options_.optionString = const_cast<char*>( optionString.c_str() );

    // initializing of JVM initial arguments:
    JavaVMInitArgs arguments_;
    memset( &arguments_, 0, sizeof( arguments_ ) );
    arguments_.version = JNI_VERSION_1_6;
    arguments_.nOptions = 1;
    arguments_.options = &options_;
    arguments_.ignoreUnrecognized = 0;

    // creating JVM or attaching to JVM:
    long status;
    /* is there any running VMs in the process? */
    JavaVM* createdVMs[1] = { nullptr };
    jsize numberOfVMs;
    status = JNI_GetCreatedJavaVMs(createdVMs, 1, &numberOfVMs);
    /* END OF is there any running VMs in the process? */
    if( numberOfVMs != 0 )
    {   // if VM already runs:
        jvm_ = createdVMs[0]; // get the VM
        jvm_->AttachCurrentThread((void**)&env_, NULL); // attach to the VM
    }
    else
    {   // if VM does not run:
        status = JNI_CreateJavaVM( &jvm_, (void**)&env_, &arguments_ ); 
    }

    if ( status == JNI_ERR )        
        throw std:: exception("Error: unable to create Java Virtual Machine.\n");

    FindClass("ChartBuilder");
}

但那还不是全部。当运行主Java项目(Java-&gt; C ++中的第一个 - &gt; Java)时,我遇到了以下问题:无法找到指定的类ChartBuilder。这是我附加到现有VM,但此虚拟机不知道此类的路径。请记住,当我在C ++中创建VM时,我明确指定了路径。为了解决这个问题,我现在要在运行主Java项目时另外指定类路径。

就是这样。我唯一不喜欢的是在运行主Java项目时需要指定ChartBuilder的类路径,但这个对我来说并不重要,尽管我想知道如何避免这种需求。也许有人知道吗?