0

我有一个 WPF 应用程序,它在特定模式下每 0.5 秒向 UI 显示一个文本字符串。我注意到,当这种情况发生时,内存使用量会缓慢但稳定地增加,并且永远不会释放,如果我让它运行足够长的时间,它将耗尽内存并崩溃。

绘图的代码如下:

public void DrawDisplay( DrawingContext dc, Size size )
{
    ...

    // Draw Text
    var fontSize = 46.0;
    FormattedText ft = new FormattedText(
        message,
        CultureInfo.GetCultureInfo( "en-us" ),
        FlowDirection.LeftToRight,
        new Typeface( "Franklin Book" ),
        fontSize,
        Brushes.Black );

    ft.MaxTextWidth = size.Width - 2;
    ft.TextAlignment = TextAlignment.Center;

    // don't draw outside of box
    ft.MaxTextHeight = size.Height;

    // Center
    var height = ( size.Height - ft.Height ) / 2;

    dc.DrawText( ft, new Point( 0, height ) );

    ...
}    

文本使用以下代码部分绘制在画布上:

DrawingVisual dv = new DrawingVisual();
var size = new Size( canvas.Width, canvas.Height );

using( DrawingContext dc = dv.RenderOpen() )
{
    // draw a transparent rect so the text doesn't stretch (fixes size)
    dc.DrawRectangle( Brushes.Transparent, null, new Rect( 0, 0, size.Width, size.Height ) );

    RadioInterface.DrawDisplay( dc, size );
}

canvas.Background = new VisualBrush( dv );

我可以通过仅注释掉“dc.DrawText(...”行。这样做,应用程序的内存使用是完全平坦的。除此之外,我不知道该尝试什么。我尝试搜索与 DrawText 相关的内存泄漏,但没有找到任何结果,并且我的函数中使用的代码几乎与 MSDN 站点上的 DrawText 示例相同。

有没有人看到这个或看到我做错了什么?

  • 我尝试使用 CLRProfiler,但我对它不是很熟悉,而且内存泄漏太慢了,我无法从中获取任何有用的信息(可能是对工具缺乏了解)。
4

1 回答 1

2

因此,经过更多阅读和重新阅读,我注意到这篇博客文章中的以下评论:https ://blogs.msdn.com/b/jgoldb/archive/2008/02/04/finding-memory-leaks-in- wpf-based-applications.aspx?Redirected=true

“这是仅存在于 3.5 SP1 版中的 WPF 中的一个泄漏。当在软件渲染模式下的 Viewport3D 中使用 VisualBrush、WriteableBitmap 或某些选择的其他类时,就会发生这种情况。”

我使用的是 Viewport,而不是 Viewport3D,但我使用的是软件渲染,如果我按照帖子中的建议将 VisualBrush 更改为 SolidColorBrush 以测试泄漏,它就会消失。此外,从 DrawingVisual 转换为 DrawingGroup 也修复了泄漏。

将第二个代码块更改为以下内容修复了泄漏:

DrawingVisual dg = new DrawingGroup();
var size = new Size( canvas.Width, canvas.Height );

using( DrawingContext dc = dg.Open() )
{
    // draw a transparent rect so the text doesn't stretch (fixes size)
    dc.DrawRectangle( Brushes.Transparent, null, new Rect( 0, 0, size.Width, size.Height ) );

    RadioInterface.DrawDisplay( dc, size );
}

canvas.Background = new DrawingBrush( dg );

我还尝试使用 DrawingVisual 类对象并一遍又一遍地重复使用它,而不是每次绘制时都创建一个新对象,这也修复了泄漏。

编辑:我使用 DrawingVisual 的最初原因是与我尝试的替代方案(包括 DrawingGroup)相比,它导致 cpu 使用率最低。差别不大,但基本一致。

于 2012-11-29T23:45:25.830 回答