2013-07-14 3 views
3

온라인 및 개인 테스트에서 배웠 듯이 양식의 종결 자 (System.Windows.Forms.Form)는 GC에 의해 호출되지 않습니다. Form GC.SuppressFinalize()의 Dispose() 내부에서 파이널 라이저가 다시 호출되지 않도록 호출됩니다.winform이 가비지 수집되었는지 어떻게 확인합니까?

Exapmle :

public partial class UpdateForm : Form 
{ 
    public UpdateForm() 
    { 
     InitializeComponent(); 

     // Listen to the event of some model 
     Database.OnDataUpdated += new EventHandler(DataBase_OnDataUpdated); 
    } 

    ~UpdateForm() 
    { 
     // Never gets called. 
    } 

    private void DataBase_OnDataUpdated(object sender, EventArgs e) 
    { 
     // Update data on this form 
    } 
} 

그러나 방송 위의 예로서, 만약 폼 커넥트 일부 모델 (+ =)는 이벤트와 분리되지 않는다 - 폐기에 (=) 이벤트() Dispose()가 호출 되더라도 양식은 결코 가비지 수집되지 않습니다. 그런 다음

int[] dummyArray = new int[1024 * 1024 * 128]; // Comsume 128MB memory 

내가의 메모리 프로필을보고 :

내가 양식 수집 된 쓰레기가 정말 있는지 확인하기 위해 할 것은 내가 다음과 같이 메모리를 많이 소비하는 형태로 내부에 큰 배열을 만들 것입니다 Windows의 작업 관리자에서 양식을 삭제 한 후 GC.Collect()를 호출 할 때 메모리 사용량이 감소되었는지 확인하십시오.

내 방법이 현명하지 않습니다. 다른 스마트 한 방법이나 양식이 실제로 가비지 수집되는 것을 확인하는 도구가 있는지 궁금합니다. 감사.

+0

finalizer가 호출되지 않아도 양식에 여전히 가비지 수집됩니다. 그런데 파이널 라이저를 왜 부르겠습니까? 파이널 라이저에 넣을 수있는 것은'Dispose' 메소드에 넣지 말아야 할 사항입니까? – hvd

+0

혼란스러운 죄송합니다. 파이널 라이저가 호출되기를 원하는 것은 아닙니다. 양식이 가비지 수집되었는지 확인하고 싶습니다. 즉 양식에서 사용하는 모든 메모리가 해제되어야합니다. 나는 보통 객체가 가비지 컬 렉트인지 여부를 확인하기 위해 파이널 라이저 (finalizer)를 사용한다. – Paul20

답변

0

당신은 사용하여 폼에 약한 참조를 유지할 수 WeakReference class :

var weakref = new WeakReference(form); 

쓰레기 수집에서 개체를 방지하지 않으며, 당신이 있었는지 확인하기 위해 해당 속성을 사용할 수있는 약한 참조 :

if (weakref.IsAlive) { /* not yet garbage collected */ } 

양식에이 작업을 수행하기 위해 파이널 라이저가 필요하지 않습니다.

+0

감사합니다. 이것은 내가 찾고있는 것입니다 : 객체 (반드시 형태 일 필요는없는)가 아직 살아 있는지를 탐지하는 일반적인 방법. 예를 들어 오도하는 것처럼 양식을 사용하는 것이 궁금합니다. – Paul20

+0

위와 같이 WeakReference를 사용하여 실험을했습니다. GC.Collect()를 호출 한 후에도 양식이 다른 참조가 없을 때 양식이 가비지 수집되지 않았 음을 확인했습니다. 내 생각에 WeakReference는 양식을 가비지 수집 할 수 있는지 여부를 결정합니다. 따라서 GC.Collect()를 호출 한 직후 양식이 가비지 수집 될 것이라는 보장은 없습니다. – Paul20

+0

@ Paul20 아니요, WeakReference는 개체 (양식)가 가비지 수집되지 않도록합니다. 비록 당신이해야한다하더라도 가비지 수집되지 않는 양식을 안정적으로 보여주는 간단한 예제를 올려 놓을 수 있다면, 나는 기꺼이 살펴볼 것입니다. – hvd

3
Database.OnDataUpdated += new EventHandler(DataBase_OnDataUpdated); 

네, 문제입니다. 일반 진단은 이벤트 원본 개체가 이벤트 수신기 개체를 out-lives한다는 것입니다. 즉, 양식 객체는 사용자가 닫은 후에도 데이터베이스 업데이트를 계속 수신합니다. 일반적으로 예외를 발생시키는 가장 일반적인 방법은 이벤트 핸들러가 폐기 된 컨트롤을 업데이트하려고 할 때 보일러 플레이트가 ObjectDisposedException입니다. 어떻게이 장애 모드를 피할 수 있었는지 명확하지 않습니다. 예를 들어 try/catch를 사용하여 장애 모드를 페이징하지 않았는지 확인하십시오.

그리고 예, GC 문제가 발생합니다. Database 객체에는 폼 객체에 대한 참조가 있습니다. 이벤트를 구독 할 때 참조를주었습니다. 나중에 이벤트를 다시 발생시킵니다. DataBase_OnDataUpdated() 메서드가 클래스의 인스턴스 메서드이기 때문에 필요합니다. C# 구문 설탕은 그 사실을 숨 깁니다. 간단한 이벤트 할당 문 아래에 실제 코드는이 (유효하지 않은 C# 코드)과 같습니다

var delegateObject = new EventHandler(this, &DataBase_OnDataUpdated); 
Database.OnDataUpdated = Delegate.Combine(DataBase_OnDataUpdated, delegateObject); 

그것은이 데이터베이스 개체에 폼 객체에 대한 참조를 전달 위임 생성자 호출이에게 숨겨져 . Delegate.Target 필드에이를 저장합니다. 나중에 이벤트를 발생시킬 때 사용합니다.

필연적으로 GC는 닫힌 후에도 양식 객체에 대한 참조를 볼 수밖에 없습니다. 데이터베이스 개체의 대리자 호출 목록에서이를 다시 찾습니다. 따라서 데이터베이스 개체가 가비지 수집 될 때까지 양식 개체를 가비지 수집 할 수 없습니다. 귀하의 질문에서 판단 할 때 귀하의 프로그램이 종료 될 때까지는 발생하지 않습니다. 아마도 그것은 정적 변수이기 때문일 것입니다.

이 문제를 피하는 다른 패턴이 있습니다. 예를 들어, 폼에 대한 참조를 Database 클래스에 전달할 수 있습니다.이 클래스는 알림을 수신중인 활성 폼 목록에 저장할 수 있습니다. 폼의 Disposed 이벤트를 구독하여 폼이 종료되었음을 알리고 해당 목록에서 개체를 제거 할 수 있습니다. 흥미로운 일이 발생할 때 Database 클래스가 호출하는 인터페이스를 구현하는 폼이 필요하다. 관찰자 패턴의 대칭. 그렇지 않으면 이벤트를 사용하는 것만 큼 정확하게는 아닙니다.

이제 문제의 원인을 알았으므로 문제를 해결할 수 있습니다. 간단히 명시 적으로 이벤트를 취소 : 당신이 그들의 청취자 오래 살 .NET에서 다른 이벤트 소스에 가입 할 때 코드의이 동일한 종류가 필요한 방법

protected override void OnFormClosed(FormClosedEventArgs e) { 
     Database.OnDataUpdated -= DataBase_OnDataUpdated; 
     base.OnFormClosed(e); 
    } 

참고. SystemEvents 및 Application에 의해 발생 된 이벤트와 동일합니다.

+0

질문을 읽은 방법에서 OP는 이벤트를 구독 취소 할 위치를 이미 알고 있으며 실제로 이벤트를 수정하는 방법을 찾고 있습니다. 문제 (다른 참조로 인해 양식이 가비지 수집되지 않도록). 실제로 OP가 언급 할 때 Dispose()를 구독 취소하는 것은 OnFormClosed()보다 좋을 것입니다. Dispose()는 일반적으로 양식이 표시되기 전에 예외가 throw 된 경우에도 일반적으로 호출되기 때문입니다. 당신은 (아주) 잘 쓰여진 대답을 올렸지 만, 나는 약간 다른 질문에 대한 답을 생각합니다. – hvd

+0

@ 한스 : 귀하의 상세하고 유용한 답변을 주셔서 대단히 감사합니다. 나는 여러 가지 새로운 것을 배웠다. 그러나 hvd의 대답은 내가 찾던 것에 더 가깝습니다. 미안하지만 분명히 내 질문을 설명하지 못할 수도 있습니다. – Paul20