0

特定のモードで 0.5 秒ごとにテキスト文字列を UI に表示する WPF アプリがあります。これが発生すると、解放されることのないメモリ使用量がゆっくりではあるが着実に増加し、長時間実行するとメモリが不足してクラッシュすることに気付きました。

描画を行うコードは次のとおりです。

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のリークです。これは、VisualBrush、WriteableBitmap、またはその他の一部のクラスがソフトウェアレンダリングモードのViewport3D内で使用されている場合に発生します。」

Viewport3DではなくViewportを使用していますが、ソフトウェアレンダリングを使用しており、リークをテストするために投稿で提案されているようにVisualBrushをSolidColorBrushに変更すると、表示されなくなります。さらに、DrawingVisualからDrawingGroupに変換すると、リークも修正されます。

コードの2番目のブロックを次のように変更すると、リークが修正されました。

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 に答える