我想知道是否存在围绕 CroppedBitmap 和 RenderTargetBitmap 的 .net EventHandler 泄漏。这让我做了一个巨大的噩梦!

我的 WPF 应用程序以 60fps 的速度运行始终运行的渲染调用。我注意到一段时间后,渲染的内容变得越来越慢。

经过大量调查,包括在 Visual Studio 中进行分析和使用 ANTS 内存分析器,我将范围缩小到使用 CroppedBitmap。

我有一些简单的 demonstration of problem 代码,其中包括...

RenderTargetBitmap srcBitmap = new RenderTargetBitmap((int)scaledWidth, (int)scaledHeight, 96, 96,     PixelFormats.Default);
RenderTargetBitmap destBitmap = new RenderTargetBitmap((int)scaledWidth, (int)scaledHeight, 96, 96,     PixelFormats.Default);

<code loop>
{...
    DrawingVisual DV = new DrawingVisual();
    DrawingContext DC = DV.RenderOpen();

    var srcRec = new Int32Rect(x,y,w,h);
    var srcCrop = new CroppedBitmap(srcBitmap, srcRec);

    var destRec = new Rect(.....);
    DC.DrawImage(srcCrop, destRec);

    DC.Close();
    destBitmap.Render(DV);

    DC = null;
    DV = null;
...}

在使用 srcBitmap 调用 CroppedBitmap 之后,srcBitmap 将添加一个事件处理程序。具体来说,如果您将其分解为更精细的级别,则设置 CroppedBitmap.Source = srcBitmap 将添加此事件处理程序。

CroppedBitmap 具有 DownloadCompleted、DownloadFailed、DownloadProgress 事件。我猜它是 DownloadCompleted。

检查 EventHandler 的数量(使用 srcBitmap/RenderTargetBitmap 上的 _downloadEvent 属性),每次调用 CroppedBitmap 时,这确实增加一 - 并且永远不会下降。我只能得出结论,CroppedBitmap 正在向 RenderTargetBitmap 添加一个永远不会被删除的事件处理程序。运行一段时间后,最终在 RenderTargetBitmap 上出现了 x000 个事件处理程序,我认为 .net 正在通过并导致我的速度下降。

我终其一生都无法弄清楚该怎么做!图像被设置在一个简单的图像控件上,没什么特别的。

我已经尝试从发生这种情况的时间开始追踪到 .net 框架的深处,一行一行地逐步执行,但是当调试器开始命中优化的 .net 库时迷路了,无法进一步挖掘。

位图的表示很简单......
Content.Source = srcBitmap;
....
<Image x:Name="Content" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RenderOptions.BitmapScalingMode="LowQuality" Stretch="None" IsHitTestVisible="False"></Image>

为了清楚起见,举个例子,代码可以在没有渲染、没有绘制图像等的情况下运行——只需要新的 CroppedBitmap... 代码来显示这种行为。为完整起见,上面包含了其他行。没什么区别。

上面的示例是针对 .NET Framework 4.7.2 运行的,以确保最新版本存在此问题。

我还尝试卡住 CroppedBitmap,以防万一。显然不是。事实上,调用 srcCrop.Freeze 导致 srcBitmap.isFrozen 为真! erm ..... 所以看起来 CroppedBitmap 改变了它被裁剪的位图?

找不到有关上述内容的任何信息、帮助、文章等:(

请注意,这不是您在支持论坛中提到的 RenderTargetBitmap 内存泄漏,这是另一回事。在没有 CroppedBitmap 的情况下运行此代码,它很好。我在几个地方使用了 RenderTargetBitmaps,一切都很好(我也已经考虑到了那篇文章中描述的内存使用量增加,我已经在调用 GC.Collect 等)。我还重用了我的 RenderTargetBitmaps,因此它们只创建一次。 (可能是为什么当多个 CroppedBitmap 应用于它们时事件处理程序会堆积起来)。

我已经尝试使用反射器来阻止正在创建的事件处理程序,以便我可以手动删除它们,但是(尽管互联网上有各种示例)无法掌握它们隐藏的任何地方来执行此操作。一定在某个地方!

任何人都知道我可以做些什么来解决这个问题?

提前感谢您的帮助...

最佳答案

您可以使用带有适当 Viewbox 的 ImageBrush,而不是使用 CroppedBitmap:

var viewbox = new Rect(
    x * 96 / srcBitmap.DpiX,
    y * 96 / srcBitmap.DpiY,
    w * 96 / srcBitmap.DpiX,
    h * 96 / srcBitmap.DpiY);

var srcBrush = new ImageBrush
{
    ImageSource = srcBitmap,
    Viewbox = viewbox,
    ViewboxUnits = BrushMappingMode.Absolute,
};

// instead of DC.DrawImage(srcCrop, destRec);
DC.DrawRectangle(srcBrush, null, destRec);

关于c# - WPF CroppedBitmap + RenderTargetBitmap = EventHandler 泄漏问题和卡住问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52591080/

10-10 15:18