7

多数のウィンドウ コントロール (ボタンやラベルなど) を作成するアプリケーションを作成しています。それらはすべて関数を通じて動的に作成されています。私が抱えている問題は、コントロールを削除して破棄すると、それらがメモリから削除されないことです。

void loadALoadOfStuff()
{
    while(tabControlToClear.Controls.Count > 0)
        tabControlToClear.Controls[0].Dispose();
    //I even put in:
    GC.Collect();
    GC.WaitForPendingFinalizers();
    foreach(String pagename in globalList)
        tabControlToClear.Controls.Add(MakeATab(pagename));
}

TabPage MakeATab(string tabText)
{
    TabPage newT = new MakeATab();
    newT.Text = tabText;
    //Fill page with controls with methods like this
    return newT;
}

なんらかの理由で、これでメモリが戻ってこないので、プロセスが 5 回実行されると、メモリ不足違反が発生します。私は処分に異議を唱えて管理するのは初めてですが、膨大なネットを調べてもまだ何の兆候もありません。

更新: ユーザー オブジェクトの作成と破棄 (タスク マネージャー) を見ていて、タブ ページを作成し、クリック ハンドラーを追加し、パネルを追加し、クリック ハンドラー、ツールチップ、およびバックイメージを備えた 2 つのボタンを追加していることに気付きました (ここにあると思います)。問題は)。アプリは 8 つの新しいアイテムを作成すると言っていますが、破棄を実行すると、メモリから 4 つしか削除されません。イベント ハンドラーを削除しようとしてきましたが、違いはないようです。

解決済み!!! パネルに新しいアイテムを追加するとき、ツールチップを渡していました (ばかげていますが、学習中です)。同じ問題を抱えている他の人のために、(以下の人々からのコメントと指示のおかげで。コントロールを本当に破棄するために発見しました(私が間違って言っていることに気付いたので))は次のとおりです。

1: ツールのヒントがある場合は、アクセス可能であることを確認してください。私がしたことをしないでください!例えば:

これは間違っています!

TabPage MakeATab(string tabText)
{
    TabPage newT = new MakeATab();
    ToolTip myTip = new ToolTip();
    newT.Text = tabText;
    //Fill page with controls with methods like this
    myTip.SetToolTip(newT, "Something to say");
    return newT;
}

これを行うと、ツールチップへのポインターが失われ、ツールチップは接続されているオブジェクトの子ではないため (むしろ、ツールチップはコントロールを強く参照します)、コントロールを破棄しても、アクセスできないツールチップは、オブジェクトを存続させます。

2: まず、toolTip.RemoveAll() を呼び出します。これにより、コントロールへの関連付けがすべて削除されます。このヒントを他のコントロールに使用していた場合は、ツール ヒントが失われていることに注意してください。

3: ベース コントロールから内部コントロールを削除します。

4: カスタム イベント ハンドラーをすべて削除します。

5: 最後に、オブジェクトを破棄します。私はそれを非常にうまく行う簡単な再帰関数を作りました。

    private void RecursiveDispose(Control toDispose)
    {
        while (toDispose.Controls.Count > 0)
            RecursiveDispose(toDispose.Controls[0]);

        if (toDispose.BackgroundImage != null)
            BackgroundImage = null;

        if (toDispose.GetType() == typeof(Button))
            toDispose.Click -= [Your Event];
        else if (toDispose.GetType() == typeof(TabPage))
            toDispose.DoubleClick -= [Your Event];
        else if (toDispose.GetType() == typeof(Label))
            toDispose.MouseMove -= [Your Event];

        toDispose.Dispose();
    }

これは非常に大雑把で、おそらくもっと良い方法があるでしょう。助けてくれてありがとう。プロジェクト全体を保存しただけかもしれません。

4

4 に答える 4

6

また、参照をクリアする必要があります。

while(tabControlToClear.Controls.Count > 0)
{ 
    var tabPage = tabControlToClear.Controls[0];
    tabControlToClear.Controls.RemoveAt(0);
    tabPage.Dispose(); 

    // Clear out events.

    foreach (EventHandler subscriber in tabPage.Click.GetInvocationList())
    {
        tabPage.Click -= subscriber;
    }
}
于 2010-01-12T06:09:19.457 に答える
4

このコード ブロックでは、Dispose を呼び出していますが、参照は削除していません。

while(tabControlToClear.Controls.Count > 0)
    tabControlToClear.Controls[0].Dispose();

コントロールをガベージ コレクションの対象にするには、コントロールへのすべての参照 (Controls コレクション、登録済みのイベント ハンドラー、その他の参照) を削除する必要があります。

于 2010-01-12T06:08:32.687 に答える
0

これまでのところ、オブジェクトが解放されていない理由の1つとして、質問に対するすばらしい回答がたくさんありました。これらはすべて、確認する価値のあるものです。

ただし、このタイプの問題が発生した場合は、メモリプロファイラーを使用してオブジェクトへの参照を追跡します。最後にメモリプロファイラーを調べたときは、ANTSメモリプロファイラーRedGateから)が最高の1つでした。(彼らは、このような単一の問題を調査するのに十分な長さの14日間のテールを実行します。)

これがウィークイベントパターンが使用される理由の1つですが、それはまったく新しい質問になります。

(UIを動的に変更するときのUIオブジェクトの存続期間は地雷原であり、タスクマネージャーがコードが期待どおりに機能していることを確認するのに適しています)

于 2010-01-12T09:22:41.640 に答える
0
void loadALoadOfStuff()
{
    while(tabControlToClear.Controls.Count > 0)
        tabControlToClear.Controls[0].Dispose();
    //I even put in:
    GC.Collect();
    GC.WaitForPendingFinalizers();
    foreach(String pagename in globalList)
        tabControlToClear.Controls.Add(MakeATab(pagename));
}

テストメソッドの最後にすべてのタブインスタンスを再割り当てしているように見えるので、最初にそれらを破棄しても明らかにメリットはありません。最後の 2 行をスキップして、それが役立つかどうかを確認してください。

于 2010-01-12T06:08:58.360 に答える