If I execute the code below, OutOfMemoryException
occurs at either the line
using (Bitmap bitmap1 = new Bitmap(FrameToFilePath(interval.Start - 1)))
or the line
using (Bitmap bitmap2 = new Bitmap(FrameToFilePath(interval.End + 1)))
when the inner for statement executed about 1000 times.
However, I don't know why OutOfMemoryException occurs. I think I have written enough using
to dispose Bitmap
objects. Where does the memory leak occurs?
class Program
{
static void Main(string[] args)
{
// Some code to initialize List<Interval> intervals
Parallel.ForEach(intervals, interval =>
{
using (Bitmap bitmap1 = new Bitmap(FrameToFilePath(interval.Start - 1)))
using (Bitmap bitmap2 = new Bitmap(FrameToFilePath(interval.End + 1)))
{
for (int i = interval.Start; i <= interval.End; i++)
{
ColorMatrix colorMatrix = new ColorMatrix(); // Identity matrix
colorMatrix.Matrix33 = (i - interval.Start + 1F) / (interval.Span + 1F); // Alpha
using (ImageAttributes imageAttributes = new ImageAttributes())
using (Bitmap intermediate = new Bitmap(bitmap1.Width, bitmap1.Height, PixelFormat.Format32bppArgb))
using (Graphics graphics = Graphics.FromImage(intermediate))
{
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
graphics.DrawImage(bitmap1, 0, 0);
graphics.DrawImage(bitmap2, new Rectangle(0, 0, intermediate.Width, intermediate.Height), 0, 0, bitmap2.Width, bitmap2.Height, GraphicsUnit.Pixel, imageAttributes);
intermediate.Save(FrameToFilePath(i), ImageFormat.Png);
}
}
}
});
}
static string FrameToFilePath(int frame)
{
return string.Format(@"C:\(some path)\frames\frame-{0:00000}.png", frame);
}
}
class Interval
{
public int Start { get; set; }
public int End { get; set; }
public int Span { get { return End - Start + 1; } }
}
EDIT: OK. Maybe it's because Parallel.ForEach
spawns tasks before other tasks ended, so that more and more tasks are started but Bitmap
s were not GCed since the tasks were not ended. Well, if this is the case, how to fix it to avoid OutofMemoryException? I am not sure if this is the case yet though...
I ran into a similar (but not similar enough for me to want to mark this as a duplicate) issue myself. What you can do is set the ParallelOptions.MaximumDegreeOfParallelism
to not create extra tasks if it sees work is stalled.
Parallel.ForEach(intervals,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
(interval) =>
{
//...
});
The reason you are getting this problem is the thing you are bound by is not the CPU but the IO of the drive during the reading of the file returned from FrameToFilePath
. This causes a low CPU % and Parallel.ForEach
detects that low % and tries to spawn more tasks to bring the usage up to 100%. Setting the max parallelism tells it to stop trying to reach 100% once a set number of tasks has been created. You could use a number larger than Environment.ProcessorCount
but your main bottleneck is your file IO.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With