2015-10-22 81 views
0

我正在开发使用JavaCV,OpenCV的Java接口的OMR(光学标记识别)应用程序。该应用程序对200张图像运行正常,但之后无法为我的代码中的IplImage分配内存。当我尝试克隆imgx并将其分配给imgxc1时,会出现分配错误。您可以为其提供程序修复吗?增加堆大小似乎是一个临时解决方案?JavaCV内存不足,未能分配内存

这里是初始化代码(在异常发生时):

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; 
} 

这里是清理代码:

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

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

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

} 

堆栈跟踪:

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) 
+0

错误看起来像问题不是堆空间限制达到,但没有足够的内存 - Java想分配更多,但操作系统无法给予更多。 –

+0

当这个错误发生时,公羊总数为4 gb的80%。这似乎不是一个公羊问题。当页面计数器为200时,应用程序在任务管理器中占用了340 MB。 – afnan1992

+0

这显然是一个RAM问题,正如@JiriTousek所说,不是Java的堆,因此增加堆大小甚至都不应该有帮助。 – Kayaman

回答

3

代码如下奇怪的。您正将IplImage对象分配给您的变量,只能立即覆盖它们。你还漏水至少一个大概的原生资源在下面的情况:

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

,将其与cvCreateImage创建原始imgxc1对象必须不再引用,但你没有释放资源。

如果Java中引用的工作原理并不清楚,我建议你在继续工作之前先做一些工作。您将摆脱冗余的双重任务,并且代码也会更清晰。

编辑:由于我已经浪费了时间,我们一行一行去看init()

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 
} 

的代码显示了Java的一个巨大的误解,但如果没有参与本机资源,它只会导致这将然后由垃圾收集处理一些额外的对象创建。

+0

我确实在释放方法中释放了引用,但您对冗余双重分配是正确的。 – afnan1992

+0

@ afnan1992不,你不知道。你不再有对原始'imgxc1'的引用,所以你无法释放它。否则,垃圾收集器将释放它,但由于它具有本地资源,它不能。如果您打算从此创建一个合适的应用程序,我强烈建议让基础知识正确。 – Kayaman

+0

本地资源的使用使其有点混乱。 imgxc1是一个实例变量,为什么我没有参考原始imgxc1?如果你能在这里教育我会很高兴。 – afnan1992