在多个jni调用中保持某种c ++对象的存活

Dav*_*Guo 6 c++ java java-native-interface

我的java代码将调用存在的c ++代码来解析文件.它会生成一个保存很多数据的对象.我将调用jni的第二种方法来访问这些数据,当我调用第二种方法时,我必须再次解析文件.这显然是正确的行为.

有办法处理这个吗?顺便说一句:我刚接触c ++.

mka*_*aes 9

我不确定我是否理解你的问题是正确的.但我想你想要做的是在多个jni调用上保持某种c ++对象的存活.

你可以做多件事.首先解析文件并将c ++对象存储在全局变量中.这是最简单的解决方案,但不是一个好的解决方案.

您还可以将c ++对象的生命周期移动到java中.

jlong java_some_class_jni_method(...)
{
    .... parse your text file ....
    MyParseclass* cls = new MyParseclass(...);
    ....
    return (jlong) cls;
}
Run Code Online (Sandbox Code Playgroud)

但请记住,您需要再次删除此本机c ++类.所以你需要一个jni方法,并确保调用它.

void java_some_calls_jni_method(..., jlong clsPtr)
{
    MyParseclass* cls = (MyParseclass*)clsPtr;
    ... do maybe do something with cls and access the data...
    delete cls; // do not use the jlong again in any call
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句:如果你发布一些代码会更有帮助.但我希望这里的伪代码有点帮助.


Jai*_*tes 5

这个问题是非常相似,这一个

这是我在 C++ 上保持对象存活以便从多个 JNI 调用中引用它们的解决方案:

爪哇

在 Java 方面,我正在创建一个带有long指针的类,以保留对 C++ 对象的引用。将 C++ 方法包装在 Java 类中,允许我们在多个活动中使用 C++ 方法。请注意,我正在构造函数上创建 C++ 对象,并在清理时删除该对象。这对于防止内存泄漏非常重要:

public class JavaClass {
    // Pointer (using long to account for 64-bit OS)
    private long objPtr = 0;

    // Create C++ object
    public JavaClass() {
        createCppObject();
    }

    // Delete C++ object on cleanup
    public void cleanup() {
        deleteCppObject();
        this.objPtr = 0;
    }

    // Native methods
    public native void createCppObject();
    public native void workOnCppObject();
    public native void deleteCppObject();

    // Load C++ shared library
    static {
        System.loadLibrary("CppLib");
    }

}
Run Code Online (Sandbox Code Playgroud)

C++

在 C++ 方面,我定义了创建、修改和删除对象的函数。值得一提的是,我们必须使用对象new并将delete其存储在 HEAP 内存中,以使其在 Java 类实例的整个生命周期中保持活动状态。我也存储指针CppObject中直JavaClass,使用getFieldIdSetLongField以及GetLongField

// Get pointer field straight from `JavaClass`
jfieldID getPtrFieldId(JNIEnv * env, jobject obj)
{
    static jfieldID ptrFieldId = 0;

    if (!ptrFieldId)
    {
        jclass c = env->GetObjectClass(obj);
        ptrFieldId = env->GetFieldID(c, "objPtr", "J");
        env->DeleteLocalRef(c);
    }

    return ptrFieldId;
}

// Methods to create, modify, and delete Cpp object
extern "C" {

    void Java_com_test_jnitest_JavaClass_createCppObject(JNIEnv *env, jobject obj) {
        env->SetLongField(obj, getPtrFieldId(env, obj), (jlong) new CppObject);
    }

    void Java_com_test_jnitest_JavaClass_workOnCppObject(JNIEnv *env, jobject obj) {
        CppObject* cppObj = (CppObject*) env->GetLongField(obj, getPtrFieldId(env, obj));

        // Write your code to work on CppObject here
    }

    void Java_com_test_jnitest_JavaClass_deleteCppObject(JNIEnv *env, jobject obj) {
        CppObject* cppObj = (CppObject*) env->GetLongField(obj, getPtrFieldId(env, obj));

        delete cppObj;
    } 

}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 与 Java 不同,C++ 没有垃圾收集,并且对象将存在于 HEAP 内存中,直到您使用delete.
  • 我正在使用GetFieldID,SetLongFieldGetLongField来存储来自 C++ 的对象引用,但您也可以jlong像其他答案中讨论的那样存储来自 Java的对象指针。
  • 在我的最终代码中,我将JavaObject类实现为 aParcelable以便将我的类传递给使用Intent附加功能的多个活动。