Can';t从c+调用java方法+;JNI中的包装器 我在JNI和C++是新的。我有一些api,它需要一些处理程序的共享指针来订阅一些消息。我可以在“主”C++方法中调用我的处理程序中的方法,但是当我从C++包装器调用它时,我会得到JVM错误和我的应用程序崩溃。我的本机方法是next: public native int subscribe(Handler handler);

Can';t从c+调用java方法+;JNI中的包装器 我在JNI和C++是新的。我有一些api,它需要一些处理程序的共享指针来订阅一些消息。我可以在“主”C++方法中调用我的处理程序中的方法,但是当我从C++包装器调用它时,我会得到JVM错误和我的应用程序崩溃。我的本机方法是next: public native int subscribe(Handler handler);,java,c++,pointers,java-native-interface,Java,C++,Pointers,Java Native Interface,Java处理程序类: public class Handler { public void call(String m1, String m2) { System.out.println("call: " + m1 + " " + m2); } } JNI实现: JNIEXPORT jint JNICALL Java_com_lib_NativeClient_subscribe (JNIEnv* env, jobject thisObj, job

Java处理程序类:

public class Handler {
public void call(String m1, String m2) {
    System.out.println("call: " + m1 + " " + m2);
}
}

JNI实现:

JNIEXPORT jint JNICALL Java_com_lib_NativeClient_subscribe (JNIEnv* env, jobject thisObj, jobject javaHandler) {

jclass handlerClass = env->GetObjectClass(javaHandler);
jmethodID call = env->GetMethodID(handlerClass, "call", "(Ljava/lang/String;Ljava/lang/String;)V");
const std::string &message1 = "message1";
const std::string &message2 = "message2";
jstring javMessage1 = env->NewStringUTF((const char* )message1.c_str());
jstring javMessage2 = env->NewStrbingUTF((const char* )message2.c_str());
env->CallVoidMethod(javaHandler, call, javMessage1, javMessage2);

JavaWrapperHandler javaWrapperHandler = JavaWrapperHandler(env, javaHandler);
std::shared_ptr<JavaWrapperHandler> handlerSharedPointer = std::make_shared<JavaWrapperHandler>(javaWrapperHandler);

return some::lib::subscribe(handlerSharedPointer);
};
当主题调用“call”方法时,我收到JVM错误:

Java运行时环境检测到一个致命错误:

pc=0x7694d8a4、pid=5681、tid=5702时的SIGSEGV(0xb)

JRE版本:OpenJDK运行时环境(Zulu11.31+16-CA)(11.0.3+7)(构建11.0.3+7-LTS) Java虚拟机:OpenJDK客户机虚拟机(11.0.3+7-LTS,混合模式,串行gc,linux arm) 有问题的框架: V[libjvm.so+0x3e58a4]获取方法id(JNIEnv\u,jclass,char const*,char const*,bool,Thread*)>>[clone.isra.149]+0x288


怎么了?提前感谢。

我们将进一步介绍@PaulMcKenzie的评论

您需要替换:

JavaWrapperHandler javaWrapperHandler = JavaWrapperHandler(env, javaHandler);
std::shared_ptr<JavaWrapperHandler> handlerSharedPointer = std::make_shared<JavaWrapperHandler>(javaWrapperHandler);
JavaWrapperHandler-JavaWrapperHandler=JavaWrapperHandler(env,javaHandler);
std::shared_ptr handlerSharedPointer=std::make_shared(javaWrapperHandler);

std::shared\u ptr handlerSharedPointer=std::make\u shared(env,javaHandler);

您违反了JavaWrapperHandler定义中的三条规则,但您可以跳过修复(因为修复它对于全局引用来说并不简单),只要您确保对象除了通过指针引用之外不会出现。

最后,我编写了工作代码。在本机方法中,需要检索并保存JVM变量(可以在线程之间共享)以检索JNIenv(不能在线程之间共享),而在另一个线程中需要它:

JNIEXPORT jint JNICALL Java_com_lib_NativeClient_subscribe (JNIEnv* env, jobject thisObj, jobject javaHandler) {
static JavaVM *jvm;
int status = env->GetJavaVM(&jvm);
    if(status != 0) {
        std::cout << "Failed to receive JavaVm instance" << std::endl;
    }
std::shared_ptr<JavaWrapperHandler> handlerSharedPointer =
std::make_shared<JavaWrapperHandler>(jvm, javaWrapperHandler);
return some::lib::subscribe(handlerSharedPointer);
};
JNIEXPORT jint JNICALL Java_com_lib_NativeClient_subscribe(JNIEnv*env,jobject thisObj,jobject javaHandler){
静态JavaVM*jvm;
int status=env->GetJavaVM(&jvm);
如果(状态!=0){
std::cout NewGlobalRef(处理程序);
}
~JavaWrapperHandler(){}
虚拟无效调用(常量std::string和message1、常量std::string和message2){
JNIEnv*env=nullptr;
自动结果=vm->GetEnv((void**)和env,JNI\u版本1\u 6);
如果(结果==JNI_附加){

std::cout请对此进行调查:
JavaWrapperHandler JavaWrapperHandler=JavaWrapperHandler(env,javaHandler).<代码> javaWrAPPrPANDELLUT//Cux>类不遵循.Cuth.javaWrAPPrPANDROLLTER /COMPE中的析构函数中放置断点,并确保在完成赋值时不调用析构函数。基本上任何具有用户定义的析构函数的C++类最好有用户定义的复制构造函数和ASS。Igment运算符,否则这是一个等待发生的错误陷阱。这些调用发生在哪些线程上?您不能跨不同线程共享
JNIEnv*
。请参阅@Michael Thank,我将try@Michael据我所知,虚拟机变量已经定义。我如何获得虚拟机?我个人将收到的
JavaVM*
保存在
JNI\u OnLoa中在一个全局变量中,不同于<代码> JNENV**/COD>,跨线程共享一个<代码> javavm */CODE不是问题。谢谢你的回复。我真的不明白当我在构造函数中实例化包装器或者写的时候会发生什么。我知道java,不知道C++。无论如何,这也不起作用。我也得到同样的错误。但是我在我的原始代码中,在析构函数中有日志,我看到在我的代码中,析构函数是在构造函数之后调用的。但是现在析构函数在任何情况下都不会调用,您应该确保(可能是通过日志记录)只创建了一个JavaWrapperHandler实例,并且在调用调用方法之前不会调用析构函数(在任何情况下……)
std::shared_ptr<JaveWrapperHandler> handlerSharedPointer = std::make_shared<JavaWrapperHandler>(env, javaHandler);
JNIEXPORT jint JNICALL Java_com_lib_NativeClient_subscribe (JNIEnv* env, jobject thisObj, jobject javaHandler) {
static JavaVM *jvm;
int status = env->GetJavaVM(&jvm);
    if(status != 0) {
        std::cout << "Failed to receive JavaVm instance" << std::endl;
    }
std::shared_ptr<JavaWrapperHandler> handlerSharedPointer =
std::make_shared<JavaWrapperHandler>(jvm, javaWrapperHandler);
return some::lib::subscribe(handlerSharedPointer);
};
    class JavaWrapperHandler : public some::lib::Handler {
JavaVM *vm;
jobject javaHandler;
public:
JavaWrapperHandler(JavaVM *gen_vm, jobject handler) {
       vm = gen_jvm;
       JNIEnv *env = nullptr;
       vm->GetEnv((void**)&env, JNI_VERSION_1_6);
       javaHandler = env->NewGlobalRef(handler);
    }

~JavaWrapperHandler() {}

virtual void call(const std::string &message1, const std::string &message2) {
        JNIEnv *env = nullptr;
        auto result = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
        if (result == JNI_EDETACHED) {
                std::cout << "Thread detached." << std::endl;
                if (vm->AttachCurrentThread((void**)&env, NULL) == JNI_OK) {
                    std::cout << "Attach current thread to vm" << std::endl;
                } else {
                    std::cout << "Failed to attach thread." << std::endl;
                }
            } else if (result == JNI_EVERSION) {
            std::cout << "Unsupported JNI version." << std::endl;
            }

    jclass handlerClass = env->GetObjectClass(javaHandler);
    jmethodID call = env->GetMethodID(handlerClass, "call", "(Ljava/lang/String;Ljava/lang/String;)V");  // Here I get error
    jstring javMessage1 = env->NewStringUTF((const char* )message1.c_str());
    jstring javMessage2 = env->NewStringUTF((const char* )message2.c_str());
    env->CallVoidMethod(javaHandler, call, javMessage1, javMessage2);

};
};