首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何修复“双重释放或损坏”错误?

如何修复“双重释放或损坏”错误?
EN

Stack Overflow用户
提问于 2021-07-09 12:40:48
回答 1查看 155关注 0票数 0

我一直在使用JNI在Java语言中使用C++库。

操作系统: Ubuntu 16.04

代码:

代码语言:javascript
复制
JNIEXPORT jint JNICALL Java_FocasUser_Focas2_getMacroDataArray
(JNIEnv *env, jobject instance, jint handle, jint startIndex, jint endIndex, jdoubleArray jArr) {

    int len = env->GetArrayLength(jArr);
    IODBMR *macro;
    macro = (IODBMR *) malloc(8 + (8 * len));

    clock_t before = clock();
    if (PrintLogCat) LOGGER.debug("cnc_rdmacror.. start Index: [%d]\t endIndex:[%d]\t",1);
    short ret = cnc_rdmacror(handle, startIndex, endIndex, 8 + (8 * len), macro);

    int elapsedTime = calcElapsedTime(before, clock());
    loggerStream << "[" << "cnc_rdmacror" << "]=" << ret << "\tElapsed Time ms : " << elapsedTime;
    fileLogger(loggerStream.str(), LOG_FILE_WRITE_COND(elapsedTime));
    
    loggerStream.str("");

    jdouble *arr = env->GetDoubleArrayElements(jArr, 0);
    double temp = 0;

    if (ret == EW_OK) {

        for (int idx = 0; idx <= endIndex - startIndex; idx++) {
            temp = macro->data[idx].mcr_val;
            for (int i = 0; i < macro->data[idx].dec_val; i++) {
                temp = temp / 10;
            }
            arr[idx] = temp;
        }
    } else {

        env->ReleaseDoubleArrayElements(jArr, arr, 0);

        free(macro);
        free(arr);
        macro = NULL;
        arr = NULL;
        env->DeleteLocalRef(instance);
        if (PrintLogCat) LOGGER.error("getMacroValue pmc error : %d", ret,1);
        return -1;
    }

    env->ReleaseDoubleArrayElements(jArr, arr, 0);


    free(macro);
    free(arr);

    arr = NULL;
    macro = NULL;
    
    env->DeleteLocalRef(instance);

    return 0;
}

“双重释放或损坏”出现在" free (arr)“行。我在"free(arr)“之前进行了初始化,然后它是可以的,但我不确定它是否是好的。我该怎么解决它呢?

提前谢谢你,

日志:https://www.evernote.com/l/AtWkcucPzCZMN4b61B9rvNLCZazK95mk3Eo/

EN

回答 1

Stack Overflow用户

发布于 2021-07-09 13:00:58

正如评论中提到的,通过使用std::vector而不是使用mallocfree的手动内存管理,该函数变得更加简单。不仅更简单,而且内存泄漏的可能性变得最小,如果不是完全消除的话。

另外,arr不是使用malloc分配的,因此调用free(arr);是不正确的。

下面是重写(未测试)的函数,它完全消除了对free()的所有调用

代码语言:javascript
复制
#include <vector>
//... 
struct LocalRefHandler
{
    jobject *m_pObject;
    JNIEnv *m_pEnv; 

    LocalRefHandler(JNIEnv* pEnv, jobject* instance) : 
                      m_pEnv(pEnv), m_pObject(instance) {}

    // Release the resources  
    ~LocalRefHandler() { m_pEnv->DeleteLocalRef(*m_pObject); }
};

JNIEXPORT jint JNICALL Java_FocasUser_Focas2_getMacroDataArray
(JNIEnv *env, jobject instance, jint handle, jint startIndex, jint endIndex, jdoubleArray jArr) {

    // This will automatically call DeleteLocalRef when the function exits 
    LocalRefHandler refHandler(env, &instance); 

    int len = env->GetArrayLength(jArr);

    // This will clean up the memory for us when the function returns 
    std::vector<char> vc(8 + (8 * len));

    // point to the underlying data
    IODMBR* macro = static_cast<IODMBR*>(vc.data());

    clock_t before = clock();
    if (PrintLogCat) LOGGER.debug("cnc_rdmacror.. start Index: [%d]\t endIndex:[%d]\t",1);
    short ret = cnc_rdmacror(handle, startIndex, endIndex, 8 + (8 * len), macro);

    int elapsedTime = calcElapsedTime(before, clock());
    loggerStream << "[" << "cnc_rdmacror" << "]=" << ret << "\tElapsed Time ms : " << elapsedTime;
    fileLogger(loggerStream.str(), LOG_FILE_WRITE_COND(elapsedTime));
    
    loggerStream.str("");

    jdouble *arr = env->GetDoubleArrayElements(jArr, 0);
    double temp = 0;

    if (ret == EW_OK) {
        for (int idx = 0; idx <= endIndex - startIndex; idx++) {
            temp = macro->data[idx].mcr_val;
            for (int i = 0; i < macro->data[idx].dec_val; i++) {
                temp = temp / 10;
            }
            arr[idx] = temp;
        }
    } else {
        env->ReleaseDoubleArrayElements(jArr, arr, 0);
        if (PrintLogCat) LOGGER.error("getMacroValue pmc error : %d", ret,1);
        return -1;
    }

    env->ReleaseDoubleArrayElements(jArr, arr, 0);
    return 0;
}

无论函数返回的原因或位置如何,std::vector都会在函数返回时自动释放内存。

这很重要的原因是,无论函数返回到哪里,std::vector都会自动“释放”内存。这包括由于某种原因抛出异常的情况。因此,您不仅不必担心多个return点,即使抛出异常,向量也会释放内存。

如果要使用RAII,这种编程方法是必不可少的。

由于抛出异常的可能性较高,因此获取的任何资源(如分配的内存、文件句柄、各种JNI结构等)都很重要。必须在退出JNI函数时清除。与手动清理的多个try/catch块相比,使用在销毁时自动清理的对象要容易得多。

例如,您在多个地方调用env->DeleteLocalRef(instance);。如果抛出一个异常,并且您没有获得调用env->DeleteLocalRef的机会,该怎么办?JNI编程是RAII技术几乎必不可少的最好的例子。

请注意,LocalRefHandler是一个创建的结构,当此类型的对象被销毁时,将调用DeleteLocalRef。一旦从JNI环境指针和实例创建了refHandler变量,您就可以看到,我们不再需要在return点处添加分散在代码中的DeleteLocalRef调用--一旦refHandler超出作用域,无论函数退出的原因是什么,都将调用DeleteLocalRef

您还可以创建一个类似的类来处理env->GetDoubleArrayElementsenv->ReleaseDoubleArrayElements,这样您就可以在函数退出时自动清理这些资源。

底线是,您应该为JNI目的构建您自己的这些小型RAII对象的代码库,以便随时可以使用它们。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68311370

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档