2009-05-18 2 views
3

큰 응용 프로그램에서 GDI 리소스 누수를 조사하고 있습니다. 이러한 문제가 어떻게 발생했는지에 대한 이해를 돕기 위해 의도적으로 '새는'응용 프로그램을 만들었습니다. 여기에 100 펜 객체의 생성을 초래할해야 간단한 사용자 컨트롤입니다 : 내 객체의 인스턴스를 생성하고 폼에 추가 그러나Windows Forms에서 GDI 누수를 어떻게 만들 수 있습니까?

 
public partial class TestControl : UserControl 
{ 
    private List pens = new List(); 

    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(object sender, PaintEventArgs e) 
    { 
     for (int i = 0; i < 100; i++) 
     { 
      e.Graphics.DrawLine(pens[i], 0, i, Width, i); 
     } 
    } 
} 

가, 나는 현재 참조 윈도우 작업 관리자 내 응용 프로그램을보고 ~ 37 개의 GDI 개체. 반복적으로 새 TestObject 사용자 정의 컨트롤을 폼에 추가하면 여전히 ~ 37 개의 GDI 개체 만 볼 수 있습니다.

여기에 무슨 일이 일어나고 있습니까? 나는 System.Drawing.Pen의 생성자가 새로운 GDI 객체를 사용하여 새로운 Pen을 생성하기 위해 GDI + API를 사용할 것이라고 생각했다.

여기에 너트가 있어야합니다. GDI 개체를 만드는 간단한 테스트 응용 프로그램을 작성할 수 없다면 어떻게 누출시킬 수 있습니까?

도움을 주시면 감사하겠습니다.

안부, 콜린 E.

+0

이상한 문제가 있습니다. 동의합니다. 여부를 확인 했습니까? GDI 개체 수를 37 회 이상 줄이면 * 37에서 감소합니까? – Noldorin

+0

예 - 37 개의 GDI 개체가 간단한 테스트 응용 프로그램 자체의 오버 헤드와 관련이있는 것 같습니다. 위의 코드에서 루프의 수와 아무 관련이 없습니다. 나는 OregonGhost (아래)가 GDI +가 GDI 핸들을 사용하고 있지 않다는 것을 알고 있다고 생각한다. 거기에 몇 가지 문서가 있었으면 좋겠어. –

답변

2

은 GDI +는 GDI 핸들 사용합니까? 나도 잘 모르겠지만 어딘가에 .NET System.Drawing 구현이있다. 맨 처음 GDI를 사용한다.

그러나 어쩌면 AQTime과 같은 프로파일 러를 사용하여 누수를 찾을 수 있습니다.

큰 앱에서 GDI 핸들이 누출되는 것을 어떻게 확인 하시겠습니까? 작업 관리자의 개수가 많습니까? 그렇다면 항상 GDI + 또는 GDI를 사용하고 있습니까? 컨트롤을 여러 번 만들면 테스트 앱 GDI 핸들 수가 증가합니까?

+0

응답 해 주셔서 감사합니다. 그렇습니다, GDI +가 항상 GDI 핸들을 사용하지 않는다는 것이 내 의심이었습니다. 큰 응용 프로그램이 GDI 핸들을 유출한다고 확신합니다. 많은 수 (> 500)를 사용하며 시간이 지남에 따라 증가합니다. GDI +를 항상 사용하고 있는지 여부에 관계없이 우리는 GDI + 만 사용한다고 가정하는 System.Drawing 만 사용합니다. 감사합니다. –

+1

... 이와 관련하여 System.Drawing.Pen이 GDI 핸들을 사용하지 않으면 어떤 리소스를 삭제합니까? 미안, 내 질문이 세 개가 되었다면! –

+0

나는 실제로 확신하지 못한다. 언급 한 것처럼 어딘가에서 GDI를 사용하는 System.Drawing 구현이 있고 일반적으로 System.Drawing은 GDI +를 사용할 것으로 기대합니다. Windows CE 등에서 사용했을 수도 있습니다. 또한 창 핸들 (폼 및 컨트롤)을 생성하면 GDI 핸들 수를 늘릴 수 있는지 여부도 확실하지 않습니다. 많은 경우에 내가 어떤 종류의 핸들을 유출하고 있었을 때, 그것은 GDI +가 아닌 누출 된 컨트롤 때문이었습니다. – OregonGhost

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 개체 하늘 로켓을 참조하십시오 ...

희망이 도움이됩니다.

+1

안녕 Denis ... 좋은 시도지만, 당신은 실제로 이것을 테스트 해 봤나? 나는 그것을 풀어 주었고 응용 프로그램은 여전히 ​​소수의 GDI 객체 만 사용했습니다. 이것은 말이되지 않습니다! –

0

나는 다음과 같은 블로그는이 질문에 대답했다고 생각 명시 적으로 암시 적으로 자신의 확정에 의해 폐기해야 배치되지

Using GDI Objects the Right Way

GDI는 개체를. 는

(밥 파월은 GDI+ FAQ에서이 문제를 언급했다) 그러나 CLR의 가비지 수집기가 너무 빨리 우리가 심지어 윈도우 작업 관리자에서 메모리 사용량의 변화를 볼 수 없습니다 GDI 리소스를 제거 할 수 있는지 의심한다. 어쩌면 현재의 GDI + 구현은 GDI를 사용하지 않을 수도 있습니다.

더 많은 GDI 개체를 생성하기 위해 다음 코드를 시도했습니다. 하지만 여전히 GDI 핸들 수의 변경 사항을 볼 수 없습니다.당신은 .NET에서 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); 
     } 
    } 
} 
1

, 다음 단지 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) 

Blingo blango, 당신은 GDI 펜을 누출하고 있습니다.

잘 모르겠 음 이유가 GDI 누출을 만들려고합니다. 그러나 귀하의 질문에 WinForm에서 GDI 누출을 만드는 방법을 물었습니다 - 그래서 거기에 있습니다.

+0

네이티브 코드 (P/Invoke)에서는 작동하지만 매니지드 GDI/GDI + 구현에서는 작동하지 않습니다. GDI/GDI + 리소스를 수집하는 .NET 가비지와 관련이 있다고 생각합니다. – IDWMaster

+0

@IDWMaster : .NET 가비지 수집기는 네이티브 리소스 (예 : GDI 핸들)를 "수집"할 수 없습니다. P/Invoke를 사용하여 GDI 핸들을 할당하는 모든 .net 코드는 P/Invoke를 수행하여이를 해제합니다. 다행히도 .NET 프레임 워크의 모든 객체가이를 처리합니다. 가비지 컬렉터는 그와 아무 관련이 없습니다. –

+0

GC는 객체에 소멸자를 호출 할 수 있습니다. 차례로 관리되지 않는 리소스를 해제합니다. – IDWMaster

0

저는 컴파일러가 하나의 핸들 만 사용한다고 생각합니다.

델파이에서 많은 글꼴을 만드는 경우 메모리를 가져옵니다.
하지만 WinAPI CreateFont()을 사용하면 GDI 개체를 사용합니다.

0

양식에 두 개의 단추를 만듭니다. 각 단추 안에 다음 코드를 추가하십시오. 한 단추에서 Dispose 메서드를 주석 처리합니다.

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

Dispose가있는 버튼에는 누출이 표시됩니다. 다른 하나는 Dispose가 사용자와 GDI 핸들을 동일하게 유지하는 것을 보여줍니다.

This은 아마 내가 찾은 가장 좋은 페이지 일 것입니다.

관련 문제