我正在使用opencvsharp在windows窗体应用程序中进行一些图像处理,在确保GC能够在适当的时间进行收集时遇到了问题。这会在我用完进程内存时导致异常。我通过遵循各种建议修复了这个问题(把所有打开的cv iDisposables放在using块中,避免不必要的分配等)但当我转移到批处理时,我仍然在大量图像后耗尽内存。
遵循opencv论坛上的一些建议,我将代码放入一个try..catch.. finally序列中,期望GC.Collect()解决这个问题。
private void procDB_Click(object sender, EventArgs e)
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK && Directory.Exists(_srcFolder))
{
_dstFolder = folderBrowserDialog1.SelectedPath;
string[] files = Directory.GetFiles(_srcFolder);
for (int i = 0; i < files.Length; i++)
{
try
{
if (Path.GetExtension(files[i]).ToLower() == ".jpg" ||
Path.GetExtension(files[i]).ToLower() == ".png" ||
Path.GetExtension(files[i]).ToLower() == ".gif" ||
Path.GetExtension(files[i]).ToLower() == ".bmp")
{
//process and save new files with 'converted ' tag in file name
using (Mat currentImage = ConformInputImage(Cv2.ImRead(files[i], ImreadModes.Color)))
{
using (_convMatBGR = ConvertImage(_srcMatBGR, currentImage))
{
string outFileName = Path.Combine(_dstFolder, Path.GetFileNameWithoutExtension(files[i])) + "_conv" + Path.GetExtension(files[i]).ToLower();
_convMatBGR.ImWrite(outFileName);
}
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
i--;
}
finally { GC.Collect(); }
}
}
}
然而,它仍然会遇到异常,但现在我可以告诉它继续,它会很高兴地对任何数量的图像这样做。这产生了如下所示的内存使用:
斜坡上的每一步都是一个正在处理的新图像,直到遇到异常为止,此时它会清除所有垃圾,当我关闭消息框时,它会继续处理。垃圾似乎确实被收集了,但在遇到异常之前没有释放任何内存-如何修复它,使它永远不会遇到异常?n
1条答案
按热度按时间xsuvu9jc1#
在绝大多数情况下,你不需要手动调用
GC.Collect
。它会在内存不足之前自动运行。如果你遇到内存不足异常,很可能是内存泄漏。如果内存使用在异常后下降,很可能是异常导致了一些引用被释放,* 这 * 允许GC收集内存。我想先说:
1.检查是否需要释放
Cv2.ImRead
的结果。即,是否记录了ConformInputImage
,以便在释放结果对象时释放其输入?1.拍摄一个内存快照并检查对象表。我希望在任何时候只有一个或两个
Mat
对象是活动的。如果超过这个数量,您就发现了泄漏。1.获取两个内存快照并比较它们,是否有任何类型的对象在两个快照之间的计数增加?这可能是泄漏的候选对象。
请注意,在处理本机库时,您可能需要对释放对象提高警惕。任何托管 Package 都应实现终结器,以确保最终释放本机对象,即使您忘记调用dispose也是如此。但这并不总是能做到的,即使做到了,终结器也可能不会立即运行,甚至根本不能保证运行。