我正在尝试围绕第三方c ++库编写JNI包装,以便可以直接从Java使用它。下面的代码示例显示了我用来包装c ++对象的模式。我已经成功使用了这种模式几次,但是每次尝试在其上调用方法时,都会有一个对象给我SIGSEGV。
主要区别在于,在正常工作的类中,我自己调用了新的WhateverNativeType()并返回了指针地址,但是在失败的类中,我正在调用的工厂方法正在执行一些逻辑来构造类。当我将工厂代码复制到我的方法中并自己调用新方法时,它解决了该问题,并且我不再得到SIGSEGV。
因此,当我调用factory方法时,可以在方法中使用该对象,但是一旦我的方法返回该引用,该引用将不再有效。我以为可能是在我对createNativeObject()和getVersion()的调用之间的几毫秒内就收集了垃圾,所以我尝试将其放入静态向量,但这没有帮助。
我的问题是,为什么我的createNativeObject()方法返回后,本机对象超出范围?有没有办法可以使它继续可用而不绕过工厂方法?
我的Java类如下:
package com.example.jni;
public class Example {
private static final native long createNativeObject();
private static final native String getVersion(long address);
public static void main(String[] args) {
long address = createNativeObject();
System.out.println("Version: " + getVersion(address);
}
}
我的C ++代码如下:
#include <jni.h>
#include <iostream>
#include "com_example_jni_Example.h"
#include <third_party_stuff.hpp>
JNIEXPORT jlong JNICALL Java_com_example_jni_Example_createNativeObject(
JNIEnv *jenv, jclass jClass) {
std::cout << "createNativeObject()\n";
thirdparty::NativeObject obj = thirdparty::NativeObjectCreator().create();
std::cout << "Object: " << &obj << "\n";
std::cout << "Version: " << obj.getVersion() << "\n";
return reinterpret_cast<jlong>(&obj);
}
JNIEXPORT jstring JNICALL Java_com_example_jni_Example_getVersion(
JNIEnv *jenv, jclass jClass, jlong address) {
std::cout << "getVersion()\n";
thirdparty::NativeObject *obj =
reinterpret_cast<thirdparty::NativeObject *>(address);
std::cout << "Object: " << obj << "\n";
std::cout << "Version: " << obj->getVersion() << "\n";
return jenv->NewStringUTF(obj->getVersion().c_str());
}
输出看起来像这样:
createNativeObject()
Object: 0x7f9d07e52060
Version: 19154
getVersion()
Object: 0x7f9d07e52060
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f4e684c8b4a, pid=6683, tid=0x00007f4e868c9700
在这种情况下,本机对象包装了一个指向抽象类型的指针,并将其所有方法调用委托给该对象。工厂方法如下:
NativeObject NativeObjectCreator::create() {
INativeObjectPtr ptr = decideWhichSubclassToUse();
return NativeObject(ptr);
}
我的Java_com_example_jni_Example_createNativeObject工作版本如下:
JNIEXPORT jlong JNICALL Java_com_example_jni_Example_createNativeObject(
JNIEnv *jenv, jclass jClass) {
std::cout << "createNativeObject()\n";
thirdparty::INativeObjectPtr ptr =
thirdparty::NativeObjectCreator.decideWhichSubclassToUse();
thirdparty::NativeObject *obj = new thirdparty::NativeObject(ptr);
std::cout << "Object: " << obj << "\n";
std::cout << "Version: " << obj->getVersion() << "\n";
return reinterpret_cast<jlong>(obj);
}