2

以下のようなカスタムコントロールを作成しました。

public partial class TextBoxEx : TextBox
{
  public TextBoxEx()
  {
    InitializeComponent();
    Font = Utility.normalFont;
  }

   protected override void OnPaint(PaintEventArgs pe)
   {
    base.OnPaint(pe);
   }
 }
//A utility class to initialize font.   
class Utility
{

    internal static Font normalFont = new Font("Arial", 18);
}

Form1 と Form2 の 2 つのフォームがあります。この TextBoxEx が Form2 に追加されます。Form1 のボタンをクリックすると、Form2 が表示されます。

Form2 を継続的に表示して閉じると、アプリケーションで GDI リークが発生します。GDI検出ツール(Bear.exe)で解析したところ、フォントがGDIリークの原因であることが判明しました。

私の質問は、

  1. TextBoxEx の Dispose() メソッドを呼び出してもフォントが解放されない理由 (Form2 を閉じているときに、TextBoxEx の Dispose() メソッドが自動的に呼び出されます)。
  2. フォントが原因の GDI リークを解決するにはどうすればよいですか? (Font.Dispose() は TextBoxEx の Dispose() メソッドで呼び出すことはできません。コンストラクターで「パラメーターが無効です」という例外がスローされるため)。
4

1 に答える 1

3

ほとんどの描画オブジェクトは非常に安価に作成できます。たとえば、ペンやブラシの作成には 1 マイクロ秒もかかりません。そのため、描画を開始するときに常に作成し、描画が終了したら破棄する必要があります。usingステートメントは、そうすることを強くお勧めします。

ただし、Font クラスは難しいです。Windows は、要求されたフォントを使用可能なフォントのセットにマップし、TrueType アウトラインをロードするために多くの作業を行う必要があります。Winforms にはそのための解決策があり、フォントをキャッシュします。フォントを初めて使用するときは、フォントの作成費用が発生します。ただし、それを破棄することはできますが、フォント オブジェクトはフォント キャッシュに残ります。次に同じフォントを作成すると、キャッシュから非常に安価なコピーが取得されます。

これは WPF の問題でもあります。OpenType アウトラインのサポートを含む、より豊富なフォント サポートがあるためです。別の方法で解決されました.WPFは完全に別のプロセスを使用してフォントをキャッシュします。WPF アプリのフォント キャッシュ サーバーのように機能します。タスク マネージャーにこのプロセスが表示されます。これは、PresentationFontCache.exe プロセスです。

とにかく、あらゆる種類のリーク診断プログラムは、このキャッシュによって混乱するでしょう. アプリがフォントをリークしていると考え、キャッシュに保存されているフォントを確認します。使用されるフォントの数が際限なく増加し、最終的にプログラムがクラッシュする場合にのみ、実際のリークが発生します。簡単にテストできます。Windows が課すクォータは低く、プロセスは 10,000 を超える描画オブジェクトを作成できません。したがって、実際にリークが発生した場合、その割り当てに到達するためにテスト プログラムを長時間実行する必要はありません。これは、タスク マネージャーでも確認できます。表示 + 列の選択、[GDI オブジェクト] チェックボックスをオンにします。テスト プログラムの数が安定していて、数百を超えないようにしてください。

于 2013-04-28T11:56:26.450 に答える