我的应用程序通过3321次迭代执行以下任务:
通过logcat,我收到了以下消息:
Progress: 1 / 3321
Progress: 2 / 3321
.
.
.
Grow heap (frag case) to 5.597MB for 206132-byte allocation
.
.
.
Progress: X / 3321
Progress: X+1 / 3321
.
.
.
Grow heap (frag case) to 64.000MB for 206132-byte allocation
.
.
.
FATAL EXCEPTION: Thread-451 Process: com.cv.myapp, PID: 15006
java.lang.OutOfMemoryError
at com.cv.myapp.SecondModule.loadImg(Native Method)
任务1,2和3由我的第二个模块完成,任务4由我的第一个模块完成
在第二个模块中(用于加载图像,调整大小并传递1-d数据):
/* Global variable */
Mat img;
/* JNI function */
JNIEXPORT jfloatArray JNICALL
Java_cv_myapp_SecondModule_loadImg(JNIEnv* env, jclass thiz,
jstring imgPath, jint height, jint width) {
// Retrieve the string passed form JAVA
const char* img_path = env->GetStringUTFChars(imgPath, 0);
// Load image into OpenCV Mat object
img = imread(img_path, IMREAD_COLOR);
// Release the string
env->ReleaseStringUTFChars(imgPath, img_path);
// Try to resize the image if the height or width does not
// match the given parameters
if ( (img.rows != height) || (img.cols != width) )
resize( img, img, Size(height, width) );
// Get the float pointer that point to Mat data
float* data = (float*) img.data;
// Return the data from native to JAVA
jfloatArray res = env->NewFloatArray(height * width);
if (res == NULL)
return NULL;
env->SetFloatArrayRegion(res, 0, height * width, data);
return res;
}
在我的第一个模块中执行任务4的本机函数:
JNIEXPORT void JNICALL
Java_cv_my_app_FirstModule_processImg(JNIEnv* env, jclass thiz,
jfloatArray img) {
// Get the image data (float array) passed from JAVA
jboolean is_copied;
jint img_size = env->GetArrayLength(img);
jfloat* img_data = env->GetFloatArrayElements(img, &is_copied);
// Do some calculation on variable img_data,
// and storing the result to the global variable.
// Release the image data
if (is_copied == JNI_TRUE)
env->ReleaseFloatArrayElements(img, img_data, JNI_ABORT);
}
在Android中:
FirstModule first_module = new FirstModule();
SecondModule second_module = new SecondModule();
// Load image paths into variable imgSet
// Each image path can be retrieved by imgSet[i]
// 3321 iterations
for (int i=0 ; i<3321 ; ++i) {
first_module.processImg(
second_module.loadImg( imgSet[i] )
);
}
我想OutOfMemoryError
可能是由于在本机和JAVA之间传输数据,但我不确定(错误可能是由于其他原因)。
我的代码出了什么问题?
非常感谢!
编辑:
我替换了
if (is_copied == JNI_TRUE)
env->ReleaseFloatArrayElements(img, img_data, JNI_ABORT);
与
env->ReleaseFloatArrayElements(img, img_data, JNI_ABORT);
,并打印以下日志。似乎发生了垃圾收集。
Progress: 301 / 3321
Clamp target GC heap from 65.488MB to 64.000MB
Grow heap (frag case) to 64.000MB for 206132-byte allocation
Progress: 302 / 3321
Progress: 303 / 3321
Forcing collection of SoftReferences for 206132-byte allocation
GC_BEFORE_OOM freed 61959K, 96% free 3192K/65408K, paused 21ms, total 24ms
Progress: 304 / 3321
Progress: 305 / 3321
Grow heap (frag case) to 4.272MB for 206132-byte allocation
Progress: 306 / 3321
.
.
.
垃圾收集也在603次迭代后发生。
Progress: 603 / 3321
Clamp target GC heap from 64.563MB to 64.000MB
Grow heap (frag case) to 64.000MB for 206132-byte allocation
Progress: 604 / 3321
Progress: 605 / 3321
Progress: 606 / 3321
Forcing collection of SoftReferences for 206132-byte allocation
GC_BEFORE_OOM freed 61219K, 87% free 3185K/24008K, paused 34ms, total 38ms
Progress: 607 / 3321
.
.
.
但是,在下面的日志打印后应用程序崩溃了
Progress: 642 / 3321
Grow heap (frag case) to 12.474MB for 206132-byte allocation
Progress: 643 / 3321
并且没有其他日志跟随日志&#34;进度:643/3321&#34;
EDIT2:
我添加了
LOGI("Release Mat.");
img.release();
LOGI("Release Mat ... ok");
前
return res;
在第二个模块中。
日志显示
I/SecondModuleJNI: Release Mat.
I/SecondModuleJNI: Release Mat ... ok
I/FirstModuleJNI: Progress: 1 / 3321
I/dalvikvm-heap: Grow heap (frag case) to 4.816MB for 206132-byte allocation
在应用程序崩溃之前。
答案 0 :(得分:1)
if (is_copied == JNI_TRUE)
env->ReleaseFloatArrayElements(img, img_data, JNI_ABORT);
无论是否复制,都应始终调用 ReleaseFloatArrayElements()
。否则,对数组的引用计数可能不会减少,也不能进行垃圾回收。