从 Jni 调用的 C++ 析构函数上的分段错误

Segmentation fault on C++ destructor called from Jni

我正在进行一个研究项目,以构建一个提供图像处理工具的库。我需要将它从 C++ 包装到其他语言。

我目前正在使用 Jni(Java 本机接口)开发 Java 实现。

我的 C++ 核心是用单例模式构建的。 Java 调用 C++ 获取指向单例的指针。

static Kernel *getInstance()
    {
        if (!m_kernel)
            m_kernel = new Kernel;
        return m_kernel;
    }

C++ returns 指针作为 long 值。

    JNIEXPORT jlong JNICALL Java_JavaCore_openKernelInstance(JNIEnv *, jobject)
{
    Kernel* kernel=Kernel::getInstance();
    std::cout << "pointer value at open" << kernel << std::endl;
    return long(kernel);
}

Java在每个需要访问这个对象的方法中提供这个值,告诉C++对象所在的位置(它不再持有指针)。

结果

pointer address hex 10x7f0a440e3a20
pointer adress dec 139682068183584
id session1=0
id session2=1

除了 "session" 的末尾外,一切正常。当 Java 要求 C++ 关闭其工作并删除其对象时,会发生以下情况

pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
pointer delete0x7f9aa40d3660
Segmentation fault (core dumped)

尝试删除指针时存在无限循环。这是析构函数

Kernel::~Kernel(){
std::cout << "pointer delete" << m_kernel << std::endl;
delete m_kernel;

}

java代码

public static void main(String[] args){
    JavaCore jc = new JavaCore();
    long l = jc.openKernelInstance();
    int idSession = jc.openSession(l);
    int idSession2 = jc.openSession(l);
    System.out.println("pointer dec="+l);
    System.out.println("id session1="+idSession);
    System.out.println("id session2="+idSession2);
    jc.closeKernelInstance(l);
}

发生这种情况是因为您在析构函数中递归地删除了 m_kernel 对象。每次调用 delete m_kernel 时,都会调用同一个析构函数。你不应该在析构函数中删除 m_kernel,在对象上调用一次 delete 就足够了:像这样。

void closeKernelInstance() {
    delete m_kernel;
}

在这种情况下析构函数应该是空的:

Kernel::~Kernel(){
}    

顺便说一句,你可以考虑使用迈耶的单例,在这种情况下你的单例将在退出时自动销毁:

static Kernel & getInstance()
{
    static Kernel theInstance;
    return theInstance;
}