Search code examples
javaopencvimage-processingjavacvomr

JavaCV Insufficient memory, failed to allocate memory


I am developing an OMR(Optical Mark Recognition) application using JavaCV,java interface for OpenCV.The application runs fine for 200 images but after that it fails to allocate memory for IplImage in my code.The allocation error comes when I try to clone imgx and assign it to imgxc1.Can you please suggest a programmatic fix for it? Increasing the heap size seems to be a temporary solution?

Here is the initialization code(where the exception occurs):

protected boolean init () throws UnableToLoadImage{
    imgx = new IplImage();
    imgxc1 = new IplImage();
    imgxd1 = new IplImage();
    imgx = cvLoadImage(path+DR+filename);
    if(imgx == null)throw new UnableToLoadImage(path+DR+filename);
    //cvSaveImage("debug/"+filename, imgx);
    imgxc1 = cvCreateImage(cvGetSize(imgx), imgx.depth(), imgx.nChannels());
    imgxc1 = imgx.clone();//error comes here
    imgxd1 = cvCreateImage(cvGetSize(imgx), IPL_DEPTH_8U, 1);
    cvCvtColor(imgxc1, imgxd1, CV_BGR2GRAY);
    return (imgx != null && imgxc1 != null && imgxd1 != null)?true:false;
}

Here is the cleaning up code:

public void release() {
    if(imgx != null){

        imgx.release();
        imgxc1.release();
        imgxd1.release();

        cvReleaseImage(imgx);
        cvReleaseImage(imgxc1);
        cvReleaseImage(imgxd1);
    }

}

Stack trace:

OpenCV Error: Insufficient memory (Failed to allocate 6454368 bytes) in cv::OutOfMemoryError, file ..\..\..\..\opencv\modules\core\src\alloc.cpp, line 52

at org.bytedeco.javacpp.opencv_core.cvCloneImage(Native Method)
at org.bytedeco.javacpp.helper.opencv_core$AbstractIplImage.clone(opencv_core.java:1005)
at com.omr.app.OmrModel.init(OmrModel.java:200)
at com.omr.app.OmrController$2.doInBackground(OmrController.java:328)
at com.omr.app.OmrController$2.doInBackground(OmrController.java:1)
at javax.swing.SwingWorker$1.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at javax.swing.SwingWorker.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Solution

  • Your code looks weird. You're assigning IplImage objects to your variables, only to overwrite them instantly. You're also leaking at least one presumably native resource in the following case:

    imgxc1 = cvCreateImage(cvGetSize(imgx), imgx.depth(), imgx.nChannels());
    imgxc1 = imgx.clone();//error comes here
    

    The original imgxc1 object that was created with cvCreateImage has no longer references to it, but you didn't release the resources.

    If how references work in Java is unclear to you, I'd suggest you do some work on that before continuing with your work. You'll get rid of your redundant double assignment lines and the code will be clearer too.

    Edit: Since I've already wasted time on this, let's go through init() line by line.

    protected boolean init () throws UnableToLoadImage{
        imgx = new IplImage();    // Create a new IplImage() even though we won't use it
    
        imgxc1 = new IplImage();  // Same here. Just food for the garbage collector
    
        imgxd1 = new IplImage();  // Third completely unnecessary object creation
    
        imgx = cvLoadImage(path+DR+filename);  // Load an image, the previously created object in imgx is now GC food
    
        if(imgx == null)throw new UnableToLoadImage(path+DR+filename);
        //cvSaveImage("debug/"+filename, imgx);
    
        imgxc1 = cvCreateImage(cvGetSize(imgx), imgx.depth(), imgx.nChannels());  // Create an image with native resources, previous object is GC food
    
        imgxc1 = imgx.clone();    // Third time assignment to imgxc1, previous object isn't GC food since it holds native resources
        imgxd1 = cvCreateImage(cvGetSize(imgx), IPL_DEPTH_8U, 1);  // The first proper use of cvCreateImage
        cvCvtColor(imgxc1, imgxd1, CV_BGR2GRAY);  // Presumably ok
        return (imgx != null && imgxc1 != null && imgxd1 != null)?true:false;  // Doesn't need the ternary operator at all
    }
    

    The code shows a huge misunderstanding of Java, but if there hadn't been native resources involved, it would only result in some extra object creations which would then be handled by the garbage collector.