いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

ToolTipコンポーネントでメモリリーク・・・(GDI, 増加, メモリリーク, SetTooltip, Dispose, System.Windows.Forms, System.ComponentModel.Container)


WinForms結構長くやっているくせに、思いっきりハマったのでメモメモ。


他のメンバーが作成した画面だったのですが、その画面だけ動作させていると
GDIオブジェクトの数がどんどん増加していく現象が発生していました。
(そのうち、オブジェクト数が1万を超えてOutOfMemoryExceptionが発生・・・)


画像とか、いろいろ表示している画面だったので、てっきりそれが原因だと思い
いろいろ調べていたのですが、原因が特定できず・・・w


で、悩みまくってたどり着いた先が以下のURLでした。


まじで!!って思ってソースを見てみると以下のようになってました・・・。

void なんかしているメソッド()
{
    //
    // いろいろ処理・・・
    //

    ToolTip tip = new ToolTip();
    tip.SetToolTip(xx, xxxx);
}


デザイナで配置しているのではなく、処理内部で一時変数として作成して
ツールチップを設定して、そのままでした。


上記の場合、見ての通りDisposeされていません。
(デザイナで配置していないので、components変数にも追加されていません。)
且つ、何故か結構な数のToolTipコントロールを作成していたので
その分、GDIオブジェクトの数が増えていました。


上のURLにも記述してあるのですが、ToolTipコンポーネント
デザイナ上では無く、処理内で自前で作成している場合は明示的な破棄処理が必須です。
なので、以下のようにしなければなりません。
(もしくは、フォームのクローズ処理にてDisposeする等)

protected override void Dispose(bool disposing)
{
    try
    {
        if (disposing && components != null)
        {
            components.Dispose();
        }

        //
        // ToolTipの破棄.
        //
        if (_tip != null)
        {
            _tip.Dispose();
        }
    }
    finally
    {
        base.Dispose(disposing);
    }
}


回避策としては、明示的に上記のようにするか
components変数にAddしてしまうかのどちらかになると思います。
(デザイナにてToolTipを配置している場合は、自動的にcomponents変数にAddされていますので問題ありません。)


ToolTipってあまりたくさん作成することもないし、そんなに見る事はないかもしれませんが
上記のコードのように、処理内部で作成して利用している箇所を発見した場合は要注意です。


ちなみに、GDIオブジェクトの調査を行う場合は以下のツールが便利です。
今回の調査でもとてもお世話になりました。w
感謝 m(_ _)m