2009-07-14 13 views
1

이것은 WinForm MDI 응용 프로그램 문제 (.net framework 3.0)입니다. 그것은 C#에서 설명 될 것입니다. 죄송합니다. 가능한 한 명확하게하려고하기 때문에 약간 길어요.MDI WinForm 응용 프로그램 및 중복 하위 폼 메모리 누수

MDI 애플리케이션이 있습니다. 어떤 시점에서 나는 MDI 자식 폼이 하나도 공개되지 않는다는 것을 알게되었습니다. MDI 자식 폼을 만들고 보여주는 메뉴가 있습니다. MDI 자식 폼이 닫히면 파괴 된 것으로 간주되고 이로 인해 가져온 메모리는 .net으로 되돌려 야합니다. 그러나 놀랍게도 이것은 사실이 아닙니다. 모든 MDI 자식 폼 인스턴스는 메모리에 보관됩니다. 이것은 분명히 "메모리 누출"입니다. 음, 그것은 .net에서 실제 누수가 아닙니다. 닫힌 양식은 죽어야한다고 생각하지만, 어쨌든 닫힌 양식과 연결된 외부 세계에서 알 수없는 참조가 적어도 하나는 있습니다.

웹에서 기사를 읽었습니다. 어떤 사람들은 MDI 자식 폼이 닫힐 때 모든 이벤트 핸들러를 끊어야한다고 말합니다. 그렇지 않으면 일부 이벤트 핸들러가 내 양식을 유지할 수 있습니다. 일부는 폼이 닫히기 전에 DataBindings를 정리해야한다고 말합니다. 그렇지 않으면 DataBindings가 일부 글로벌 Hashtable에 대한 참조를 추가하여 내 양식을 유지합니다.

제 양식에 상당히 많은 것들이 포함되어 있습니다. 많은 이벤트 처리기 및 많은 데이터 바인딩과 많은 BindingSources 및 사용자 제어 및 HelpProvider가 포함 된 의심되는 컨트롤은 거의 없습니다. 관련된 모든 컨트롤에서 모든 이벤트 핸들러를 제거하고 모든 DataBindings 및 DataSources를 지우는 큰 메서드를 만듭니다. HelpProvider 및 사용자 컨트롤은주의 깊게 처리됩니다.

마지막으로 DataBindings 및 DataSources를 지울 필요가 없습니다. 이벤트 처리기가 확실히 문제를 일으키고 있습니다. 그리고 MDI 형식 구조는 또한 무언가에 기여합니다.

MDI 자식 폼을 만들면 닫아도 여전히 메모리에 인스턴스가 하나 있습니다. 참조는 기본 폼의 PropertyStore에서 가져온 것입니다. 즉, 주 양식이 닫히지 않는 한 (응용 프로그램이 종료 됨) 항상 메모리에 MDI 자식 폼의 인스턴스가 하나 있습니다. 다행스럽게도 자녀 양식을 열거 나 닫는 횟수가 아무리 많아도 하나의 인스턴스 만있을뿐 큰 "누출"은 없습니다.

이벤트 처리기의 경우 상황이 더욱 까다로워집니다. 그 문제를 해결해야합니다. 양식의 모든 이벤트 처리기는 익명 이벤트 처리기입니다. btnSave_Click 또한 MDI 자식 폼의 방법이다

//On MDI child form's design code... 

Button btnSave = new Button(); 

btnSave.Click += new System.EventHandler(btnSave_Click); 

예를 들면 다음과 같습니다 코드입니다. 위의 내용은 다양한 제어 및 다양한 이벤트 유형에 항상 해당됩니다. 나에게 이것은 양방향 순환 참조이다. btnSave는 이벤트 핸들러를 통해 MDI 자식 폼에 대한 참조를 유지합니다. MDI 자식 폼은 btnSave 인스턴스에 대한 참조를 유지합니다. 나에게 다시 양방향 순환 참조가 .net의 가비지 컬렉터에 문제를 일으키지 않아야한다. 즉, 양식을 폐기 할 때 명시 적으로 해당 이벤트를 단절 할 필요가 없음을 의미합니다.

btnSave.Click -= btnSave_Click; 

사실은 그렇지 않습니다. 일부 이벤트 핸들러의 경우 안전합니다. 무시하면 인스턴스가 중복되지 않습니다. 일부 다른 이벤트 처리기의 경우 메모리에 하나의 인스턴스가 남아있게됩니다 (MDI 양식 구조와 비슷한 효과가 있지만 이번에는 걸려있는 이벤트 처리기로 인해 발생 함). 다른 이벤트 처리기의 경우 메모리에서 열린 모든 인스턴스가 발생합니다. 이 세 가지 유형의 이벤트 처리기의 차이점에 대해서는 완전히 혼란 스럽습니다. 컨트롤은 같은 방법으로 만들어지며 이벤트는 같은 방식으로 첨부됩니다. 그 차이점은 무엇입니까? (차이를 만드는 이벤트 핸들 방법이라고 말하지 마십시오.) 누구든지이 유선 시나리오에 대한 경험이 있고 저에게 답이 있습니까? 고마워.

이제 보안 문제로 인해 양식을 처리 할 때 모든 이벤트 처리기를 해지해야합니다. 그것은 각 컨트롤에 대한 유사한 코드의 긴 목록 일 것입니다. 리플렉션을 사용하여 재귀 적으로 컨트롤에서 이벤트를 제거하는 일반적인 방법이 있습니까? 성능 문제는 어떻습니까?

그건 내 이야기의 끝이고 나는 여전히 내 문제의 한가운데에있다. 도움이 필요하면 고맙습니다.

답변

1

해결 방법 here으로 문제를 해결할 수 있습니다.

0

이벤트 처리기가 연결되는 개체가 자식 폼에 선언되어있는 한 자식 폼이 삭제 될 때 이벤트 처리기를 제거 할 필요는 없지만 이벤트 처리기가 연결된 개체 자식 폼 외부에 선언 된 경우 자식 폼이 삭제 될 때 이벤트 처리기를 제거해야합니다.

이 코드를 여러 번 실행 (및 btnSave하지 자식 폼에 선언 된 객체입니다)이 코드는 동일한 횟수를 실행하는

btnSave.Click += btnSave_Click;

경우

btnSave.Click -= btnSave_Click;


응용 프로그램의 어딘가에서 자식 폼을 참조하고있을 수 있으므로 가비지 수집기에서 자식 폼 개체를 제거하기 전에이 참조를 제거해야합니다.