4

大規模なアプリケーションでのGDIリソースリークを調査しています。これらの問題がどのように発生するかをさらに理解するために、意図的に「リーク」した非常に小さなアプリケーションを作成しました。これは、100個のペンオブジェクトを作成するための簡単なユーザーコントロールです。

パブリック部分クラスTestControl:UserControl
{{
    プライベートリストペン=newList();

    public TestControl()
    {{
        InitializeComponent();

        for(int i = 0; i <100; i ++)
        {{
            pens.Add(new Pen(new SolidBrush(Color.FromArgb(255、i * 2、i * 2、255-i * 2))));
        }

        this.Paint + = new PaintEventHandler(TestControl_Paint);
    }

    void TestControl_Paint(オブジェクト送信者、PaintEventArgs e)
    {{
        for(int i = 0; i <100; i ++)
        {{
            e.Graphics.DrawLine(pens [i]、0、i、Width、i);
        }
    }
}

ただし、オブジェクトのインスタンスを作成してフォームに追加すると、TaskManagerを使用してアプリケーションを見ると、現在、最大37個のGDIオブジェクトが表示されます。新しいTestObjectユーザーコントロールをフォームに繰り返し追加して、 37個までのGDIオブジェクトしか表示されません。

ここで何が起こっているのか!System.Drawing.Penのコンストラクターは、GDI + APIを使用して新しいペンを作成し、新しいGDIオブジェクトを使用すると思いました。

私はここで気が狂うに違いない。GDIオブジェクトを作成する簡単なテストアプリケーションを作成できない場合、それらをリークするテストアプリケーションを作成するにはどうすればよいですか。

どんな助けでも大歓迎です。

よろしく、コリンE。

4

6 に答える 6

2

.NETからGDIオブジェクトをリークする場合は、GDIオブジェクトを作成し、解放しないでください。

[DllImport("gdi32.dll", EntryPoint="CreatePen", CharSet=CharSet.Auto, SetLastError=true, ExactSpelling=true)]
private static extern IntPtr CreatePen(int fnStyle, int nWidth, int crColor);

CreatePen(0, 0, 0); //(PS_SOLID, 0=1px wide, 0=black)

ブリンゴブランゴ、あなたはGDIペンを漏らしています。

なぜGDIリークを作成したいのかわかりません。しかし、あなたの質問は、WinFormからGDIリークを作成する方法を尋ねました-そうです。

于 2011-07-05T01:59:51.070 に答える
2

サンプルのリソースが実際にリークしているわけではありません。Loadイベントから次のコードを削除します。

for (int i = 0; i < 100; i++)
    {
        pens.Add(new Pen(new SolidBrush(Color.FromArgb(255, i * 2, i * 2, 255 - i * 2))));
    }

Paintイベントハンドラは次のようになります。

void TestControl_Paint(object sender, PaintEventArgs e)
{
    for (int i = 0; i < 100; i++)
    {
        e.Graphics.DrawLine(new Pen(new SolidBrush(Color.FromArgb(255, i * 2, i * 2, 255 - i * 2))), 0, i, Width, i);
    }
}

これで、すべてのペイント呼び出しでリークが発生します。フォームの最小化/復元を開始し、GDIオブジェクトが急上昇するのを確認してください...

お役に立てれば。

于 2009-05-18T18:15:23.013 に答える
2

GDI+ は GDI ハンドルを使用しますか? わかりませんが、裸の GDI に依存する .NET System.Drawing 実装があることをどこかで読んだことがあります。

ただし、代わりに AQTime などのプロファイラーを使用してリークを見つけようとすることもできます。

大規模なアプリで GDI ハンドルがリークしていることをどのように確認できますか? タスク マネージャーのカウントは大きいですか? その場合、常に GDI+ を使用していますか、それとも GDI も使用していますか? コントロールを複数回作成すると、テスト アプリの GDI ハンドル数は増加しますか?

于 2009-05-18T15:14:27.327 に答える
0

フォームに 2 つのボタンを作成します。各ボタン内に、次のコードを追加します。1 つのボタンで、Dispose メソッドをコメント アウトします。

    Form _test = null;
    for (int i = 0; i < 20; i++)
    {
        _test = new Form();
        _test.Visible = false;
        _test.Show();
        _test.Hide();
        _test.Dispose();
    }

Dispose がコメントアウトされたボタンは、リークを示しています。もう 1 つの例は、Dispose によってユーザー ハンドルと GDI ハンドルが同じままになることを示しています。

これはおそらく、それを説明している私が見つけた最高のページです。

于 2014-10-14T18:14:12.920 に答える
0

コンパイラはハンドルを 1 つしか使用しないと思います。

Delphi で大量のフォントを作成する場合はメモリを使用するだけ
ですが、WinAPICreateFont()を使用する場合は GDI オブジェクトを使用します。

于 2012-08-22T07:08:33.627 に答える
0

次のブログがこの質問に答えていると思います。

GDI オブジェクトを正しく使用する

明示的に破棄されていない GDI オブジェクトは、ファイナライズによって暗黙的に破棄する必要があります。(Bob Powell もGDI+ FAQでこの問題について言及しています)

しかし、CLR ガベージ コレクターが GDI リソースをすぐに削除して、タスク マネージャーからメモリ使用量の変化を確認することさえできないかどうかは疑問です。おそらく、現在の GDI+ 実装は GDI を使用していません。

次のコードを試して、より多くの GDI オブジェクトを生成しました。しかし、まだ GDI ハンドルの数に変化は見られませんでした。

void Form1_Paint(object sender, PaintEventArgs e) 
{
    Random r = new Random();
    while (true)
    {
        for (int i = 0; i < 100; i++)
        {
            e.Graphics.DrawLine(
            new Pen(new SolidBrush(Color.FromArgb(r.Next()))), 0, i, Width, i);
        }
    }
}
于 2011-05-30T08:05:10.347 に答える