【问题标题】:C# Bitmap - Cannot find how to remove OutOfMemoryExceptionC# 位图 - 找不到如何删除 OutOfMemoryException
【发布时间】:2015-03-02 06:14:58
【问题描述】:

如果我执行下面的代码,OutOfMemoryException 会出现在任一行

using (Bitmap bitmap1 = new Bitmap(FrameToFilePath(interval.Start - 1)))

或者一行

using (Bitmap bitmap2 = new Bitmap(FrameToFilePath(interval.End + 1)))

inner for 语句执行了大约 1000 次。

但是,我不知道为什么会发生 OutOfMemoryException。我想我已经写了足够的using 来处理Bitmap 对象。内存泄漏发生在哪里?

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

编辑:好的。也许是因为Parallel.ForEach在其他任务结束之前产生了任务,所以越来越多的任务开始了,但是Bitmaps没有被GC,因为任务没有结束。好吧,如果是这种情况,如何解决它以避免OutofMemoryException?我不确定是否是这种情况......

【问题讨论】:

标签: c# memory-leaks out-of-memory


【解决方案1】:

我遇到了类似的(但不够相似,我想将其标记为重复)issue myself。您可以将ParallelOptions.MaximumDegreeOfParallelism 设置为在看到工作停滞时不创建额外任务。

Parallel.ForEach(intervals,
    new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
    (interval) =>
        {
           //...
        });

您遇到此问题的原因是您在读取从FrameToFilePath 返回的文件期间受约束的不是 CPU,而是驱动器的 IO。这会导致较低的 CPU 百分比,Parallel.ForEach 检测到较低的百分比并尝试生成更多任务以将使用率提高到 100%。设置最大并行度告诉它一旦创建了一定数量的任务就停止尝试达到 100%。您可以使用大于 Environment.ProcessorCount 的数字,但您的主要瓶颈是文件 IO。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    相关资源
    最近更新 更多