如何解决如何修复“双重释放或损坏”错误?
我一直在通过 JNI 在 Java 中使用 C++ 库。
操作系统:Ubuntu 16.04
代码:
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,0);
free(macro);
free(arr);
arr = NULL;
macro = NULL;
env->DeleteLocalRef(instance);
return 0;
}
“double free or corruption”出现在“free(arr)”行。 我在“free(arr)”之前初始化,然后没问题,但我不确定它是否正常。 我该如何解决?
非常感谢您,
日志:https://www.evernote.com/l/AtWkcucPzCZMN4b61B9rvNLCZazK95mk3Eo/
解决方法
正如评论中提到的,通过使用 std::vector
而不是使用 malloc
和 free
手动管理内存,该函数变得更加简单。
不仅更简单,而且内存泄漏的可能性也会降到最低,如果不能完全消除的话。
此外,arr
不是使用 malloc
分配的,因此调用 free(arr);
是不正确的。
这是您重写的函数(未经测试),它完全消除了对 free()
的所有调用:
#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,0);
return 0;
}
std::vector
将在函数返回时自动释放内存,无论函数返回的原因或位置如何。
这很重要的原因是无论函数在哪里返回,std::vector
都会自动“释放”内存。这包括是否因某种原因引发异常。所以不仅不用担心多个return
点,即使抛出异常,vector也会释放内存。
如果您要使用 JNI,这种编程方法,即 RAII,是必不可少的。
由于抛出异常的可能性有点高,因此必须在退出 JNI 函数时清除获取的任何资源(例如分配的内存、文件句柄、各种 JNI 结构等),这一点很重要。使用在销毁时自动清理自己的对象比处理多个 try/catch
块要容易得多,在这些块中,您需要手动清理内容。
例如,您在多个地方调用 env->DeleteLocalRef(instance);
。如果抛出异常,而您没有机会调用 env->DeleteLocalRef
怎么办? JNI 编程是几乎必须使用 RAII 技术的主要示例。
请注意,LocalRefHandler
是一个创建的结构,当该类型的对象被销毁时,会调用 DeleteLocalRef
。从 JNI 环境指针和实例创建 refHandler
变量后,您可以看到我们不再需要在 DeleteLocalRef
点处添加散布在代码中的 return
调用 -- {无论函数退出的原因是什么,一旦 DeleteLocalRef
超出范围,{1}} 都会被调用。
您还可以创建一个类似的类来处理 refHandler
和 env->GetDoubleArrayElements
,以便在函数退出时自动清理这些资源。
最重要的是,您应该为 JNI 目的构建这些小型 RAII 对象的代码库,以便它们随时可用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。