I am using opencvsharp to do some image processing in a windows forms app and am having problems ensuring that the GC can collect at the appropriate times. This is causing an exception at the point when I run out of process memory. I sort of fixed this by following various recommendations (put all open cv iDisposables in using blocks, avoid unneeded allocations etc) but when I moved on to batch processing I still ran out of memory after a number of images.
Following some advice on an opencv forum, I put my code in a try..catch...finally sequence, expecting the GC.Collect() to sort out the problem.
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(); }
}
}
}
However, it still hits the exception but now I can tell it to carry on, which it does quite happily for any number of images. This produces the memory usage shown here:
Each step on the ramp is a new image being processed until it hits the exception, at which point it clears up all the garbage and when I dismiss the message box, it carries on. The garbage does seem to be collected but without freeing up any memory until the exception is reached - how do I fix it so it never hits the exception?n
In the vast majority of cases you should not need to call GC.Collect
manually. It will run automatically before running out of memory. If you are running into out of memory exceptions it is likely that you have a memory leak. If the memory usage goes down after an exception it is likely that the exception caused some reference to be released, and that allows the GC to collect the memory.
I would start by:
Cv2.ImRead
needs to be disposed. I.e. is ConformInputImage
documented to dispose its input when the result object is disposed?Mat
objects alive at any point. If there is any more than that you have found your leak.Note that you might need to be more vigilant with disposing objects when dealing with native libraries. Any managed wrapper should implement a finalizer to ensure the native objects are eventually freed, even if you forget to call dispose. But this is not always done, and even if it is done, the finalizer might not run immediately, and is not even guaranteed to run at all.