为什么通过JNI创建的c ++对象在以后的调用中不再有效?

时间:2019-03-06 05:32:54

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

我正在尝试围绕第三方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);
}

0 个答案:

没有答案