WPF CroppedBitmap + RenderTargetBitmap = EventHandler 泄漏问题和 Freeze 问题
WPF CroppedBitmap + RenderTargetBitmap = EventHandler leak problem and Freeze problem too
我想知道 CroppedBitmap 和 RenderTargetBitmap 是否存在 .net EventHandler
漏洞。这给我带来了巨大的噩梦!
我的 WPF 应用程序 运行 总是 运行ning 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。
检查 EventHandlers 的数量(使用 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 为真!呃……所以 CroppedBitmap 似乎对它裁剪的位图进行了更改?
在上面找不到任何信息、帮助、文章等:(
请注意,这不是您在支持论坛中提到的 RenderTargetBitmap 内存泄漏,这是另外一回事。 运行 没有 CroppedBitmap 的这段代码很好。我在几个地方使用 RenderTargetBitmaps,一切都很好(而且我也已经按照那篇文章中的描述考虑了内存使用量的增加,并且我已经在调用 GC.Collect 等)。我还重用了我的 RenderTargetBitmaps,因此它们只创建一次。 (可能是为什么在应用多个 CroppedBitmap 时事件处理程序堆积起来的原因)。
我试过使用反射器来阻止正在创建的事件处理程序,以便我可以手动删除它们,但是(尽管 Internet 上有各种示例)无法找到它们隐藏的地方来执行此操作。一定在某处!
有人知道我可以做些什么来解决这个问题吗?
提前感谢您的帮助...
您可以使用带有适当 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);
我想知道 CroppedBitmap 和 RenderTargetBitmap 是否存在 .net EventHandler
漏洞。这给我带来了巨大的噩梦!
我的 WPF 应用程序 运行 总是 运行ning 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。
检查 EventHandlers 的数量(使用 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 为真!呃……所以 CroppedBitmap 似乎对它裁剪的位图进行了更改?
在上面找不到任何信息、帮助、文章等:(
请注意,这不是您在支持论坛中提到的 RenderTargetBitmap 内存泄漏,这是另外一回事。 运行 没有 CroppedBitmap 的这段代码很好。我在几个地方使用 RenderTargetBitmaps,一切都很好(而且我也已经按照那篇文章中的描述考虑了内存使用量的增加,并且我已经在调用 GC.Collect 等)。我还重用了我的 RenderTargetBitmaps,因此它们只创建一次。 (可能是为什么在应用多个 CroppedBitmap 时事件处理程序堆积起来的原因)。
我试过使用反射器来阻止正在创建的事件处理程序,以便我可以手动删除它们,但是(尽管 Internet 上有各种示例)无法找到它们隐藏的地方来执行此操作。一定在某处!
有人知道我可以做些什么来解决这个问题吗?
提前感谢您的帮助...
您可以使用带有适当 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);