我一直在使用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, 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/
发布于 2021-07-09 13:00:58
正如评论中提到的,通过使用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, 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->GetDoubleArrayElements和env->ReleaseDoubleArrayElements,这样您就可以在函数退出时自动清理这些资源。
底线是,您应该为JNI目的构建您自己的这些小型RAII对象的代码库,以便随时可以使用它们。
https://stackoverflow.com/questions/68311370
复制相似问题