Unable to free Mat object in Java

I am trying to pass a Mat Java object from C ++ using JNI . I looked at the source code of the OpenCV Java DLL, and I use the same code that uses OpenCV. When I want to release the Mat object from Java, which is created by the OpenCV Java API, it works fine, but when I want to release the Mat object that I created using the same code that the application crashes with.

I am sending codes that I use. I would really appreciate if anyone has an idea. Thanks in advance.

[EDIT]

In addition, I would like to add one more note if you look at blocks of code 3 and 4. Function definitions in Java and C ++ have the same function names, readImage0, but in 1 and 2 in C ++ the function name has an additional 1 the name on it, imread_11 and imread_1, how are these two connected? Perhaps there is an extra layer that I don't know about.

[/ EDIT]

[EDIT2]

Running on Windows 7, VC11, tried both with OpenCV 2.4.5 and 2.4.8

[/ EDIT2]

1. This is C ++ code for passing the Mat object to the OpenCV source code:

 JNIEXPORT jlong JNICALL Java_org_opencv_highgui_Highgui_imread_11 (JNIEnv*, jclass, jstring); JNIEXPORT jlong JNICALL Java_org_opencv_highgui_Highgui_imread_11 (JNIEnv* env, jclass , jstring filename) { static const char method_name[] = "highgui::imread_11()"; try { LOGD("%s", method_name); const char* utf_filename = env->GetStringUTFChars(filename, 0); std::string n_filename( utf_filename ? utf_filename : "" ); env->ReleaseStringUTFChars(filename, utf_filename); Mat _retval_ = cv::imread( n_filename ); return (jlong) new Mat(_retval_); } catch(const std::exception &e) { throwJavaException(env, &e, method_name); } catch (...) { throwJavaException(env, 0, method_name); } return 0; } 

2. This is the Java code in the OpenCV source:

 public static Mat imread(String filename) { Mat retVal = new Mat(imread_1(filename)); return retVal; } private static native long imread_1(String filename); 

3. This is my code:

 JNIEXPORT jlong JNICALL Java_tr_com_guney_opencvcpp2java_OpenCVCpp2Java_readImage0(JNIEnv *env, jclass, jstring imagePath) JNIEXPORT jlong JNICALL Java_tr_com_guney_opencvcpp2java_OpenCVCpp2Java_readImage0(JNIEnv *env, jclass, jstring imagePath) { static const char method_name[] = "OpenCVCpp2Java::readImage0()"; try { LOGD("%s", method_name); const char* utf_filename = env->GetStringUTFChars(imagePath, 0); std::string n_filename( utf_filename ? utf_filename : "" ); env->ReleaseStringUTFChars(imagePath, utf_filename); cv::Mat _retval_ = cv::imread( n_filename ); return (jlong) new cv::Mat(_retval_); } catch(const std::exception &e) { throwJavaException(env, &e, method_name); } catch (...) { throwJavaException(env, 0, method_name); } return 0; } 

4. This is my Java code:

 public static Mat readImage(String imagePath) { Mat retVal = new Mat(readImage0(imagePath)); return retVal; } private static native long readImage0(String imagePath); 

5. This is how I run the code:

 Mat image = Highgui.imread("e:/image.png"); //this works fine Highgui.imwrite("e:/imageJava.png", image); // this is to check if image is read correctly and works fine image.release(); // this works fine //system.gc(); // this also works fine Mat image2 = OpenCVCpp2Java.readImage("e:/image.png"); //this works fine Highgui.imwrite("e:/imageJava2.png", image2); // this is to check if image is read correctly and works fine image2.release(); // this throws exception! //system.gc(); // this causes application to crash! 

6. This is what is written in Exception:

 Exception in thread "main" java.lang.Exception: Unknown exception in JNI code {Mat::n_1release()} at org.opencv.core.Mat.n_release(Native Method) at org.opencv.core.Mat.release(Mat.java:1875) 

7. This is what is written in the crash report:

 Stack: [0x28880000,0x288d0000], sp=0x288cf620, free space=317k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [ntdll.dll+0x2e3be] RtlInitUnicodeString+0x196 C [ntdll.dll+0x2e023] RtlFreeHeap+0x7e C [kernel32.dll+0x114ad] HeapFree+0x14 C [opencv_java245.dll+0x48e877] Java_org_opencv_contrib_Contrib_chamerMatching_11+0x429a47 C [opencv_java245.dll+0x904f3] Java_org_opencv_contrib_Contrib_chamerMatching_11+0x2b6c3 C [opencv_java245.dll+0x6516a] Java_org_opencv_contrib_Contrib_chamerMatching_11+0x33a j org.opencv.core.Mat.n_delete(J)V+0 j org.opencv.core.Mat.finalize()V+4 v ~StubRoutines::call_stub V [jvm.dll+0xfb88b] V [jvm.dll+0x18d551] V [jvm.dll+0xfb90d] V [jvm.dll+0x96301] V [jvm.dll+0x990c9] C [java.dll+0x2100] Java_java_lang_ref_Finalizer_invokeFinalizeMethod+0x39 j java.lang.ref.Finalizer.runFinalizer()V+45 j java.lang.ref.Finalizer.access$100(Ljava/lang/ref/Finalizer;)V+1 j java.lang.ref.Finalizer$FinalizerThread.run()V+24 v ~StubRoutines::call_stub V [jvm.dll+0xfb88b] V [jvm.dll+0x18d551] V [jvm.dll+0xfba31] V [jvm.dll+0xfba8b] V [jvm.dll+0xb5e89] V [jvm.dll+0x119b74] V [jvm.dll+0x14217c] C [msvcr71.dll+0x9565] endthreadex+0xa0 C [kernel32.dll+0x1336a] BaseThreadInitThunk+0x12 C [ntdll.dll+0x39f72] RtlInitializeExceptionChain+0x63 C [ntdll.dll+0x39f45] RtlInitializeExceptionChain+0x36 Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) j org.opencv.core.Mat.n_delete(J)V+0 j org.opencv.core.Mat.finalize()V+4 v ~StubRoutines::call_stub j java.lang.ref.Finalizer.invokeFinalizeMethod(Ljava/lang/Object;)V+0 j java.lang.ref.Finalizer.runFinalizer()V+45 j java.lang.ref.Finalizer.access$100(Ljava/lang/ref/Finalizer;)V+1 j java.lang.ref.Finalizer$FinalizerThread.run()V+24 v ~StubRoutines::call_stub 
+8
java c ++ opencv jni
source share
1 answer

I found out what the problem is. I think it is quite difficult, at least for me.

The problem is that I used opencv_java248.dll, which is distributed with OpenCV and is already compiled. opencv_java248.dll is created statically, which means that after compilation it does not need any of the OpenCV DLLs (opencv_core248.dll, etc.). And I created my own dll opencvcpp2java.dll, which is also built statically, so that it will not need any DLL at runtime.

After I got an accident, I started thinking what could cause this problem. Then I realized that allocating and freeing memory is done on a completely different dll . I allocated memory using opencvcpp2java.dll and expected opencv_java248.dll to release it. And when he tried to release it, the program crashes. On the other hand, when I performed both distribution and release using opencv_java248.dll, there were no problems. So, as an intuition, I thought that allocation and deallocation should be performed on the same DLL.

After this intuition, I compiled opencv_java248.dll myself (for this you need to compile all OpenCV DLLs, this is a piece of cake when using CMake) and make it dependent on another OpenCV DLL and recompile opencvcpp2java. dll, and also make it dependent on the OpenCV DLL. Therefore, when I want to allocate memory using opencvcpp2java.dll , it allocates memory using (opencv_core248.dll) OpenCV, and when I want to free memory using opencv_java248.dll , it frees memory using the same DLL that it was created .

I am not 100% sure that this is the right solution, but it worked for me.

+3
source share

All Articles