Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
静态c++;对象并调用一个连续两次使用字符串参数的java函数会导致JVM崩溃_Java_C++_Jvm_Java Native Interface - Fatal编程技术网

静态c++;对象并调用一个连续两次使用字符串参数的java函数会导致JVM崩溃

静态c++;对象并调用一个连续两次使用字符串参数的java函数会导致JVM崩溃,java,c++,jvm,java-native-interface,Java,C++,Jvm,Java Native Interface,因此,根据我的评论员的要求,我终于找到了一个复制我错误的MCVE。因此,java java java语言使用Java语言调用JNI,并保存一个指向JNENV的指针,它用于调用Java类中的方法(从C++调用的Java类不一定是原始调用java对象,这就是为什么输入的Joobe不用于回调)。在我进一步解释之前,请允许我发布所有代码: JniTest.java package jnitest; public class JniTestJava { public static void main

因此,根据我的评论员的要求,我终于找到了一个复制我错误的MCVE。因此,java java java语言使用Java语言调用JNI,并保存一个指向JNENV的指针,它用于调用Java类中的方法(从C++调用的Java类不一定是原始调用java对象,这就是为什么输入的Joobe不用于回调)。在我进一步解释之前,请允许我发布所有代码:

JniTest.java

package jnitest;

public class JniTestJava {
  public static void main(String[] args) {

    try {
      System.load("<path-to-dll>");
    } catch (Throwable e) {
      e.printStackTrace();
    }

    DllFunctions dllFunctions = new DllFunctions();
    dllFunctions.setup();
    dllFunctions.singleIntFunctionCall();
    dllFunctions.doubleIntFunctionCall();
    dllFunctions.singleStringFunctionCall();
    dllFunctions.doubleStringFunctionCall();
  }

  public void javaStringFunction(String input){
    System.out.println(input);
  }

  public void javaIntFunction(int input){
    System.out.println(input);
  }
}
package jnitest;

public class DllFunctions{
  public native void singleIntFunctionCall();
  public native void doubleIntFunctionCall();
  public native void singleStringFunctionCall();
  public native void doubleStringFunctionCall();

  public native void setup();
}
JniTestCpp.h

#include <jni.h>
#ifndef _Included_jnitest_JniTestJava
#define _Included_jnitest_JniTestJava
#ifdef __cplusplus

extern "C" {
#endif
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_setup(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleIntFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleIntFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleStringFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleStringFunctionCall(JNIEnv* java_env, jobject);

#ifdef __cplusplus
}
#endif
#endif
#include <jni.h>

class JniTestClass {
  typedef jint(JNICALL * GetCreatedJavaVMs)(JavaVM**, jsize, jsize*);
public:
  void setup();
  void callJavaStringFunction();
  void callJavaIntFunction();
  void throwException(jthrowable ex);

private:
  jobject myObject;
  jclass myClass;
  JNIEnv* env;
};
#include "JniTestCpp.h"
#include "JniTestClass.h"

extern "C"
{
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_setup(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleIntFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaIntFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleIntFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaIntFunction();
    jniTestClass.callJavaIntFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleStringFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaStringFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleStringFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaStringFunction();
    jniTestClass.callJavaStringFunction();
  }
}
JniTestClass.h

#include <jni.h>
#ifndef _Included_jnitest_JniTestJava
#define _Included_jnitest_JniTestJava
#ifdef __cplusplus

extern "C" {
#endif
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_setup(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleIntFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleIntFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleStringFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleStringFunctionCall(JNIEnv* java_env, jobject);

#ifdef __cplusplus
}
#endif
#endif
#include <jni.h>

class JniTestClass {
  typedef jint(JNICALL * GetCreatedJavaVMs)(JavaVM**, jsize, jsize*);
public:
  void setup();
  void callJavaStringFunction();
  void callJavaIntFunction();
  void throwException(jthrowable ex);

private:
  jobject myObject;
  jclass myClass;
  JNIEnv* env;
};
#include "JniTestCpp.h"
#include "JniTestClass.h"

extern "C"
{
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_setup(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleIntFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaIntFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleIntFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaIntFunction();
    jniTestClass.callJavaIntFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleStringFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaStringFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleStringFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaStringFunction();
    jniTestClass.callJavaStringFunction();
  }
}
下面我展示了hs_err_pidXXX.log文件中的10个顶层堆栈帧:

让我惊讶的是,如果我在JniTestCpp.cpp中没有声明
JniTestClass JniTestClass
为静态对象,而是声明它并在每个方法中调用
setup()
,如下图所示,它不会崩溃,但会产生预期的结果。另外,我必须说,调用
doubleIntFunctionCall()时工作是相当奇怪的但不是
doubleStringFunctionCall()

JniTestCpp.cpp-这不会崩溃

#include <jni.h>
#ifndef _Included_jnitest_JniTestJava
#define _Included_jnitest_JniTestJava
#ifdef __cplusplus

extern "C" {
#endif
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_setup(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleIntFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleIntFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleStringFunctionCall(JNIEnv* java_env, jobject);
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleStringFunctionCall(JNIEnv* java_env, jobject);

#ifdef __cplusplus
}
#endif
#endif
#include <jni.h>

class JniTestClass {
  typedef jint(JNICALL * GetCreatedJavaVMs)(JavaVM**, jsize, jsize*);
public:
  void setup();
  void callJavaStringFunction();
  void callJavaIntFunction();
  void throwException(jthrowable ex);

private:
  jobject myObject;
  jclass myClass;
  JNIEnv* env;
};
#include "JniTestCpp.h"
#include "JniTestClass.h"

extern "C"
{
  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_setup(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleIntFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaIntFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleIntFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaIntFunction();
    jniTestClass.callJavaIntFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_singleStringFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaStringFunction();
  }

  JNIEXPORT void JNICALL Java_jnitest_DllFunctions_doubleStringFunctionCall(JNIEnv* java_env, jobject) {
    JniTestClass jniTestClass;
    jniTestClass.setup();
    jniTestClass.callJavaStringFunction();
    jniTestClass.callJavaStringFunction();
  }
}
很抱歉发了这么长的帖子,但这是我唯一能明确表达我的问题的方式

更新

在函数
void JniTestClass::callJavaStringFunction()
中,如果我将其更改为以下内容:

void JniTestClass::callJavaStringFunction() {
  jmethodID myMethod = env->GetMethodID(myClass, "javaStringFunction", "(Ljava/lang/String;)V");
  if (env->ExceptionCheck()) {
    throwException(env->ExceptionOccurred());
  }

  jstring j_string = env->NewStringUTF("String!");
  env->CallVoidMethod(myObject, myMethod, j_string);
  if (env->ExceptionCheck()) {
    throwException(env->ExceptionOccurred());
  }

  env->DeleteLocalRef(j_string);
}
现在我在使用
NewStringUTF()
创建的
jstring
上调用
DeleteLocalRef()
,程序仍会崩溃,但会打印出此异常消息:

java.lang.NoSuchMethodError: javaStringFunction

您的代码中有几个错误

  • jobject myObject
    jclass myClass
    在JNI调用中重用

    默认情况下,在JNI方法中创建的所有
    jobject
    都是本地引用。每当JNI方法返回时,所有本地引用都会自动释放

    如果要跨方法调用重用
    jobject
    (或
    jclass
    ,它也是一个对象引用),则应使用将其转换为全局引用。当不再需要全局引用时,它应该被删除,否则引用的对象将永远不会被垃圾收集

  • JNIEnv*
    被缓存

    一般来说,
    JNIEnv*
    永远不应该存储起来以供以后重用。相反,您应该使用提供的
    JNIEnv*
    作为每个JNI函数的第一个参数。或者也可以通过电话获得。请注意,每个线程都有自己的
    JNIEnv*
    ,这不适用于其他线程


  • H.Guijt:它怎么不是C++ +?H.Guijt,我只是展示了相关的代码的一部分。@ MartinRindar:你应该发布一个完整的最小的例子来复制这个问题。首先,你不检查任何返回值。您只需假设
    GetMethodID
    有效。其次,你的代码正在崩溃,你不知道如何修复它,那么你怎么知道什么是相关的呢?发帖:“我曾希望我所展示的足以让别人告诉我为什么GetMethodID()在NewStringUTF()出现时崩溃。”一般来说,它不会。如果我将您的代码插入测试项目(用其他内容替换
    myClass
    myFunction
    ),它也不会崩溃。因此,您发布的代码不足以重现问题。感谢您为我清除这些内容!周一,我将根据您的评论进行更改,并报告结果。使用NewGlobalRef将
    jobject myObject
    jclass myClass
    转换为全局引用成功。谢谢