Reputation: 95
I've run into weird problem. To keep things short: I've written an Android app that utilizes OpenCV with two Activities:
Activity1 previews front camera and on user click starts Activity2, sending current frame's address by Intent
Activity2 assigns to it's local field of type Mat clone of the frame under the given address and allows the user simple manipulations on it (namely to perform inRange method in HSV colorspace). Mat is converted to Bitmap an displayed in ImageView: this happens on Activity2 start (for original captured frame) and after each user manipulation of SeekBar.
Activity1 is a parent of Activity2, therefore clicking back button restarts Activity1. And now comes the weird part(s):
1) after some time (less than 1 minute) Activity1 crashes, with libc: Fatal signal 11 (SIGSEGV)
- as you can imagine, it does not happen when Activity2 is never started
2) if I restart Activity2 by simply returning to Activity1 and clicking again, OnCreate() and other methods from regular lifecycle are being called and the app crashes with the same fatal signal error in line when convertion from Mat to Bitmap is performed:
Utils.matToBitmap(mCapturedFrame, bm);
So, it's the first time OpenCV's function is being called after restarting an Activity. The best part is, mCapturedFrame exsists and the aformentioned method is called after loading the OpenCV library. What's more, I release() locally created Mats, as well as field that contains captured frame Mat (when I return from Activity2). The error looks like memory leak in case of Activity1, but where?!
I really can't see what I'm doing wrong here and will be glad for any suggestions. Feel free to download my java code files from here: http://speedy.sh/RMPKH/thesis.zip
Upvotes: 0
Views: 580
Reputation: 3615
If I understand this correctly, you're sending the native object address of the Mat from Activity 1 to Activity 2. Then, in Activity 2, you're doing something like this:
Mat receivingMat = new Mat(nativeAddrFromActivity1);
In this case, the problem is that you're running into a double-free error. The reason for this is non-trivial, but I will walk you through. First let's look into OpenCV's Mat implementation of that constructor:
public Mat(long addr)
{
if (addr == 0)
throw new java.lang.UnsupportedOperationException("Native object address is NULL");
nativeObj = addr;
}
Of course, the receivingMat will at some point in future run out of scope and then be collected by the GarbageCollector. In this case, the finalize method will be called. This results in a call to the native delete function of OpenCV's Mat implementation, because the finalize method is implemented as follows:
@Override
protected void finalize() throws Throwable {
n_delete(nativeObj);
super.finalize();
}
The n_delete function is defined as follows (see here):
//
// native support for java finalize()
// static void Mat::n_delete( __int64 self )
//
JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1delete
(JNIEnv*, jclass, jlong self);
JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1delete
(JNIEnv*, jclass, jlong self)
{
delete (Mat*) self;
}
From my point of view, this is a bug in OpenCV for Android. A Mat created with the native address constructor should not call the n_delete function, since it has no ownership of the native Mat header and is not responsible for cleaning it up. I cannot think of any case where you would like this behavior...
To solve your problem, you should instead convert the Mat to a bitmap, save it to a temporary file and send the path to that file from Activity 1 to Activity 2 via intent extras.
Upvotes: 2