kapry / javacv

Automatically exported from code.google.com/p/javacv
GNU General Public License v2.0
0 stars 1 forks source link

IplImage.createFrom hangs with exception after some iteration #152

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
This code throws RuntimeException:

        for(int i = 0; i < 500; ++i) {
(1)     File file = new File("test.png");
(2)     BufferedImage bimage = ImageIO.read(file);
(3)     IplImage image = IplImage.createFrom(bimage);   
(4)     //IplImage image = cvLoadImage("test.png");
        if (image != null) {
(5)         cvReleaseImage(image);
        }
        }

Here is the error message:
OpenCV Error: Bad argument (unrecognized or unsupported array type) in 
cvReleaseData, file /usr/local/OpenCV-2.3.1.install/modules/core/src/array.cpp, 
line 996
problem:java.lang.RuntimeException: 
/usr/local/OpenCV-2.3.1.install/modules/core/src/array.cpp:996: error: (-5) 
unrecognized or unsupported array type in function cvReleaseData

If I comment out line (5) then it works correctly.
If I change lines (1), (2), (3) to (4) then it works correctly so I suspect 
that createFrom has some memory leaking. 
The test.png is a 5K color image. I have tested the problem with a ~200K color 
jpg with similar results. The only difference is that error appears in the 
second iteration.

I used -Xms20971520 -Xmx20971520 java parameters during runs. I have tried to 
debug memory usage but I could not see that lack of free Java memory so I have 
no clear explanation. 

I could use a workaround saving the bufferedimage to file system and loading it 
with cvLoadImage but this is not a nice solution.

I am on Mandriva linux 2010.0 with opencv 2.3.1 using the latest javacv 
(2012-01-08).

Original issue reported on code.google.com by ricsi.sz...@gmail.com on 9 Feb 2012 at 4:22

GoogleCodeExporter commented 8 years ago
Yes, this is normal. As indicated in the README.txt file, you should call 
IplImage.release() to release manually an IplImage create with one of the 
IplImage.create*() factory method, if you do not want to wait for the garbage 
collector, *not* cvReleaseImage(). If the IplImage is created by something 
else, such as cvLoadImage(), then we need to call cvReleaseImage() on it, yes, 
that is correct.

Original comment by samuel.a...@gmail.com on 10 Feb 2012 at 5:08

GoogleCodeExporter commented 8 years ago
Yes, thanks, you are right, I have tried with image.release(); instead of line 
(5) and it works.

However it was not clear from the README.txt that I can leave the memory 
deallocation to the garbage collector or I can call image.release() explicitly 
_BUT_ I cannot call cvReleaseImage(image). Anyway checking opencv_core.java I 
see that release() calls deallocate() which calls cvReleaseImage() (after 
create() created a deallocator) so based on the source I see no difference 
between release() and cvReleaseImage(). Can you explain what I am missing?
Thanks.

Original comment by ricsi.sz...@gmail.com on 10 Feb 2012 at 8:28

GoogleCodeExporter commented 8 years ago
When calling cvReleaseImage(), since it is just a normal function, JavaCV has 
no way of knowing that memory has been released, so the garbage collector will 
try to rerelease it again once its reference goes out of scope. That's when the 
crash happens.

I could create a special cvReleaseImage() function and make it behave 
differently from the original cvReleaseImage(), but what's the point? Makes 
more sense to name it differently, thus IplImage.release()...

I guess I should add a warning about that in the README.txt file in any case, 
will do, thanks!

Original comment by samuel.a...@gmail.com on 10 Feb 2012 at 11:58

GoogleCodeExporter commented 8 years ago
Thank you for the help and the explanation!

Original comment by ricsi.sz...@gmail.com on 10 Feb 2012 at 12:03

GoogleCodeExporter commented 8 years ago
Is my unterstanding of the the working of cvLoadImage vs IplImage.create* 
correct?

1) cvLoadImage allocates some memory outside of the java heap memory which has 
to be explicitely released by cvReleaseImage or we will have a memory leak 
where the java process finally eats up all the available memory

2) The factory methods IplImage.create* will create an image wich image data 
stored in the java heap space and will be garbage collected as any "normal" 
java object. If I call cvRelease on such an image, than the allocated memory 
will be released immediately??

I have implemented a web application using cvLoadImage to load an IplImage and 
I wrap it with an OpenCVImage class. In the finalizer of this class I call 
cvReleaseImage. Is this correct? I notice, that the java process memory will 
grow much beyond the max heap setting -Xmx. I would like to prevent the 
application to use to much memory on the system

I would be glad if you could explain how the memory management works.

Thanks a lot

Rolf

Original comment by rolf....@gmail.com on 4 Dec 2012 at 8:14

GoogleCodeExporter commented 8 years ago
@rolf If you're comfortable with cvCreateImage(), cvLoadImage(), and 
cvReleaseImage(), just use that, they will behave exactly as expected from the 
documentation of the C API. IplImage.create*() allocate memory in the same 
exact way, but also register a deallocator (something like a finalizer), that 
is all. If you want to release the memory and the deallocator, call 
IplImage.release(), do not call cvReleaseImage(), because this does not 
releases the deallocator. Is this clear? About the Java heap, that has nothing 
to do with either OpenCV or JavaCV, they do not touch it, so please refer to 
the documentation of Java.

And please post your questions on the mailing list next time if possible, thank 
you.

Original comment by samuel.a...@gmail.com on 5 Dec 2012 at 1:20