1

Canvasa内で aを使用し、オーバーライドして a になる WPF プログラムがあります。これは次のようWindowになります。Graphics_Canvas

class Graphics_Canvas : Canvas
{
    private List<DrawingVisual> visuals = new List<DrawingVisual>();

    protected override int VisualChildrenCount
    {
        get { return visuals.Count; }
    }

    protected override Visual GetVisualChild(int index)
    {
        return visuals[index];
    }

    public void AddVisual(DrawingVisual visual)
    {
        visuals.Add(visual);

        base.AddVisualChild(visual);
        base.AddLogicalChild(visual);
    }

    public bool ContainsVisual(DrawingVisual visual)
    {
        return visuals.Contains(visual);
    }

    public bool HasVisuals
    {
        get { return visuals.Count > 0; }
    }

    public void RemoveAllVisuals()
    {
        for (int i = 0; i < visuals.Count; i++)
        {
            base.RemoveVisualChild(visuals[i]);
            base.RemoveLogicalChild(visuals[i]);
        }

        visuals.Clear();
    }

    public void RemoveLastVisual()
    {
        if (visuals.Count > 0)
        {
            int index = visuals.Count - 1;

            base.RemoveVisualChild(visuals[index]);
            base.RemoveLogicalChild(visuals[index]);
            visuals.Remove(visuals[index]);
        }     
    }

    public void RemoveVisual(DrawingVisual visual)
    {
        base.RemoveVisualChild(visual);
        base.RemoveLogicalChild(visual);
        visuals.Remove(visual);            
    }
}

(私はそれをオンラインのどこかから入手しましたが、少し前だったのでどこにあったか思い出せません。)

とにかく、このプログラムでは、ユーザーがGraphics_Canvas中央のマウスでドラッグすることで、に表示されているグラフィックスをパンできます。これにより、(パンを続けている限り) 次のようなものが継続的にトリガーされます。

            //get the data visual:
            DrawingVisual tempVisual = GetDataDrawingVisual();

            //first clear the current display data:
            myCanvas.RemoveVisual(dataVisual);

            //get the data visual:
            dataVisual = tempVisual;

            myCanvas.AddVisual(dataVisual);

したがって、私は継続的に削除してから再度追加しdataVisualます。

メモリの使用状況を見て気づいたのは、パニングするとメモリの使用量が増加し、再び減少する一方で、以前の状態にはまったく戻らないということです。これは、ディスプレイに何も表示されていない場合はさらに顕著であり、事実上何も追加し直さないためのメモリ使用量は数百 MB に達する可能性があり、パンが停止するとほとんどが低下します。

詳細については、が描画される をGetDataDrawingVisual()返すを追加する必要があります。これ自体は、そのメソッドの外部には保持されません。VisualRenderTargetBitmap

私の質問は、なぜこれによりメモリ使用量が大きく変化するのですか?

現在のところ、これは興味深い厄介な問題ですが、最初から利用可能なメモリがもっと限られている場合は、問題になる可能性があると予測できます。

どんな洞察も大歓迎です。

* 更新 (2013 年 3 月 21 日) *

で実験したGraphics_Canvasところ、次の方法は解放されないメモリの量にかなりの影響を与えるようです。

protected override Visual GetVisualChild(int index)
{
    return visuals[index];
}

テストとして代わりに aを返すと、new DrawingVisual()再描画が終了した後、メモリはほとんど元の場所に戻ります。

ただし、このメソッドを削除すると、Canvasが実行されなくなり、エラーが発生します。舞台裏のどこかで .NET がVisualこのメソッドから返された への参照を作成し、後で参照解除していない可能性がありますか? どうすればこれを並べ替えることができますか? (注: コードでこのメソッドを明示的に呼び出すことはありません。別の場所から呼び出されます)。

4

1 に答える 1

1

メモリ使用量が大きく変化する理由は、ガベージ コレクターがすぐに起動しないためだと思います。したがって、オブジェクトをドラッグしている間、実行されるまでメモリ使用量が増加します。

次のようにしてガベージ コレクションを強制できます。

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

そうすれば確実にわかります。

記憶が完全に戻らない理由について: いくつかのビジュアルへの参照を保持していて、それらが収集されていない可能性がありますか? プログラムの他の部分で何かがメモリを構築している可能性がありますか?

メモリ リークが発生している可能性があります。WPF のパフォーマンスと .NET Framework クライアント プロファイルに関するこの記事を確認してください。

于 2013-03-20T12:40:05.930 に答える