2

MVVM Prism を使用して記述された WPF アプリケーションがあります。たくさんのタブがあります。これらのタブは、それぞれ約 2..3 MB のメモリを消費します。クライアントは、数十個のタブを開いたり閉じたりした後、アプリケーションが最初から消費したよりもはるかに多くのメモリを消費すると不満を漏らしています。また、新しいタブを開くにはより多くのメモリが必要になるため、アプリケーションは古いタブを使用せず、代わりに新しいタブを作成します。

したがって、明らかに古いタブはガベージコレクションされません。明らかに、それらを指すリンクがいくつかあるためです。

どうすればそれらをガベージコレクションできますか? IDisposable を実装し、可能な限りすべての参照を削除する必要がありますか? Dispose メソッドもデストラクタで呼び出されるようにしますか? 不要な参照をすべて削除できるかどうかはわかりません。

この問題を解決するのに役立つ、使用できる優れたツールがあるのではないでしょうか?

4

1 に答える 1

4

これは明らかに負荷の高い質問です。メモリ消費は、メモリ リークだけが原因ではない可能性があります。すべてのアプリは異なり、特効薬はありません。そのため、役立つアイデアをいくつか紹介します。

  1. ANTS プロファイラーを入手してください。2 週間の試用期間と優れたチュートリアルがあります。ゾンビのオブジェクトなど、多くのことを示します。

  2. WPF は独り占めするので、開くタブ (消えないコントロール) が増えるほど、より多くのメモリが必要になります。XAML を調べてください。削除できますか。たとえば、ラベルの代わりに TextBlock を使用します。StackPanel 内の StackPanel、または Grid 内の Grid、stackpanel 内の Grid など、余分にネストされたコントロールを削除します。それらすべてを 1 つのグリッドに配置し、行/列を利用します。複雑なので、それを変更してみてください。たとえば、フォーカス時にアイテムの周りに境界線を描画し、凝った処理を行う場合、質問してください。各アイテムから境界線を削除し、その位置を計算して適切に配置する 1 つのコントロールを作成できますか。

  3. タブごとに同じタイプのビュー (ユーザーコントロールまたはコントロール) がありますか?インスタンスが異なるだけですか? もしそうなら、あなたはそれらをリサイクルできますか?私は 1 年以上前に、いくつかの基準のタブを作成するメニューを作成するプロジェクトに参加していました。基準は異なりましたが、ビューの種類は同じでした。さまざまな情報が注入されていました.Prismは、これらのタブごとに新しいViewコントロールを作成していましたが、これは明らかに高価です. 最終的に行ったことは、異なる ViewModel を作成することですが、その高価なビューの同じインスタンス (必要に応じて領域を削除/追加して再利用) を維持することです。これを行うには、各 ViewModel がナビゲーション上にある (サンプル)

    //detaching from Prism region allows for recycling
    public override void OnNavigatedFrom (NavigationContext navigationContext)
    {
     var view = _container.Resolve (typeof (Object), "NameOfTheView");
     if (view != null)
        navigationContext.NavigationService.Region.Remove (view);
    }
    //similarly you can readd it where your think it is nedded..
    
    public override void OnNavigatedTo (NavigationContext navigationContext)
    {
        base.OnNavigatedTo (navigationContext);
        RestoreDataState (_state);
    

    }

    このリンクは役に立ちます: http://blogs.msdn.com/b/dphill/archive/2011/01/23/closable-tabbed-views-in-prism.aspx

  4. ガベージ コレクションに関する注意: .NET ガベージ コレクタの全体的な目的は、ユーザーに代わってメモリを管理することです。ただし、非常にまれな状況では、GC.Collect() を使用してプログラムでガベージ コレクションを強制することが有益な場合があります。

    具体的には:

    a. アプリケーションが、ガベージ コレクションによって中断されたくないコード ブロックに入ろうとしているとき。

    b.アプリケーションが非常に多数のオブジェクトの割り当てを終了したばかりで、取得したメモリをできるだけ早く削除したい場合。(これは私のプロジェクトの場合でした)

    c. また: http://blogs.msdn.com/b/ricom/archive/2004/11/29/271829.aspx

すべての ViewModel に Dispose メソッドを確実に実装し、大きなものはすべて null に設定し、イベントやタイマーなどのサブスクライブを解除することを忘れないでください。GC.Collect (); を呼び出すことができます。ただし、上記の注をお読みください。複雑なオブジェクトをクリーンアップすることを忘れないでください。単に null に設定しないでください。たとえば、私の Dispose には次のようなものがあります。

ClearDisplayGrid ();

次にこれを行っていました:

private void ClearDisplayGrid ()
    {
        foreach (var r in DisplayGrid.MyItems.SelectMany (it => it.SubItems))
        {
            r.IsSelectedChanged -= ReadingIsSelectedChanged;
            r.InEditChanged -= ReadingInEditChanged;
            r.PropertyChanged -= ReadingPropertyChanged;
        }
    }
于 2012-04-19T16:51:01.333 に答える