【问题标题】:Memory leak in RenderTargetBitmapRenderTargetBitmap 中的内存泄漏
【发布时间】:2017-10-14 21:37:19
【问题描述】:

我正在使用RenderTargetBitmap 来呈现一组控件以生成 PDF。以下代码段是相关部分:

public Drawing.Image RenderPageBitmap()
{
    RenderTargetBitmap bit = null;
    Drawing.Bitmap bmp = null;
    try
    {
        bit = new RenderTargetBitmap(ImageSource.PixelWidth, ImageSource.PixelHeight, 96, 96, PixelFormats.Pbgra32);

        var viewBox = GetPageXaml(); //This method loads some prebuilt XAML from an embedded resource, setting the DataContext as needed.
        var siz = new Size(bit.PixelWidth, bit.PixelHeight);
        viewBox.Measure(siz);
        viewBox.Arrange(new Rect(siz));
        viewBox.UpdateLayout();

        var draw = new DrawingVisual();
        using (var graph = draw.RenderOpen())
            graph.DrawRectangle(new BitmapCacheBrush(viewBox), null, new Rect(siz));

        bit.Render(draw);
        bit.Freeze();

        bmp = new Drawing.Bitmap(bit.PixelWidth, bit.PixelHeight, Imaging.PixelFormat.Format32bppPArgb);

        var data = bmp.LockBits(new Drawing.Rectangle(Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, Imaging.PixelFormat.Format32bppPArgb);
        {
            bit.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
        }
        bmp.UnlockBits(data);

        return bmp;
    }
    catch (Exception)
    {
        bmp?.Dispose();
        throw;
    }
    finally
    {
        bit?.Clear();

        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
    }
}

即使在 StackOverflow 和其他论坛上关注其他答案(如清除位图和执行垃圾收集)似乎也无法解决问题。这段代码的每个循环都可能泄漏约 100MB 的内存,这意味着我很快就达到了 32 位进程的约 2GB 限制。

泄漏似乎只发生在RenderTargetBitmap.Render 方法上,即使DrawingContext.DrawRectangle 调用也不会显着增加内存使用量。

有什么办法可以解决这个问题吗?

这是通过 JetBrains 的 dotMemory 查看的内存使用情况快照。显然,.Net 堆已正确清除,但非托管内存继续增长。

【问题讨论】:

  • @Downvoter,需要解释一下吗?
  • 您是假设存在内存泄漏还是真的​​遇到了 OutOfMemoryException ?我已经更新了我的答案。顺便说一句,我没有投反对票。
  • 你怎么知道是RenderTargetBitmap有内存泄漏? viewBox 元素怎么样?在问这个问题之前,你绝对应该使用内存分析器。
  • @Clemens 我使用了内存分析器。该视图框元素被缓存,并且在该渲染调用之前和之后检查内存使用情况表明这是内存跳跃的地方。
  • @CharithJ 我确实遇到了 OutOfMemory 异常,您可以在调试器中看到内存使用量猛增。

标签: c# wpf memory-management memory-leaks rendertargetbitmap


【解决方案1】:

删除bit.Freeze();。垃圾收集不收集冻结的对象。

【讨论】:

    【解决方案2】:

    您将Bitmap 返回到某个地方。确保在完成后处理 Bitmap 实例。当内存泄漏时,您在finally 中所做的一切都是无用的。如果有引用,GC 不会收集它。

    这段代码的每个循环都可能泄漏约 100MB 的内存,这意味着我 很快就达到了 32 位进程的 ~2GB 限制。

    您是否假设存在内存泄漏?可能没有内存泄漏。我会得到一个好的内存分析工具并测试它。

    我使用过ANTS Memory profiler,我觉得它很好(试用期为 14 天)。只需执行您的逻辑几次,然后查看实例列表(如果有任何增长)。如果是这样,请查看保留图以了解它的保留情况。这会告诉你到底发生了什么。内存泄漏的根本原因有时很难猜测,幸运的是有很好的工具。

    【讨论】:

    • 内存泄漏发生在非托管内存中。建议 RenderTargetBitmaps 使用该垃圾收集技术。 Bitmap 包含在调用者的 using 块中。
    • @PeterDuniho System.Drawing.Bitmap 绝对实现 IDisposable: msdn.microsoft.com/en-us/library/8th8381z(v=vs.110).aspx
    • @la:我指的是RenderTargetBitmap。你没有显示方法声明,所以我不清楚你描述的代码是在处理不同的 Bitmap 类。
    • 我使用了 JetBrains 的 dotMemory,发现非托管内存会增长,而托管内存不会增长,这使得使用分析器几乎无法追踪
    猜你喜欢
    • 2011-10-06
    • 2013-01-25
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    • 2015-12-01
    • 2010-12-20
    相关资源
    最近更新 更多