2009-09-09 3 views
2

SimpleButton1이라는 단추가있는 단일 Windows 폼이 있다고 가정합니다. 다음 코드는 제어 할 수없는 메모리 사용량을 초래합니다. 내가 뭘 잘못하고 있니?.NET 이벤트로 인해 제어 할 수없는 메모리 사용이 발생합니다.

나의 이해는 루프의 각 반복에서, GC는 어떤 TestClass에 객체를 정리하고, 사건의에는 핸들러가 없기 때문에뿐만 아니라 모든 관련 이벤트 돌볼 것입니다

Public Class Form1 

Private Sub SimpleButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SimpleButton1.Click 
    For i = 1 To 1000000 
     Dim test1 As New TestClass    
    Next 
End Sub 
End Class 

Public Class TestClass 
    Private Event TestEvent(ByVal sender As Object) 
End Class 

IDisposable을 구현하고 For 루프의 모든 반복 끝에 test1.Dispose()를 호출 해 보았습니다.하지만 올바른 리소스를 삭제하지는 않았을 것으로 생각됩니다.

* ANSWERED : 코드에 문제가 없었으며 예상대로 실행되었습니다. 문제는 디버그 모드에서 실행 중이었기 때문에 생성 된 오버 헤드로 인해 많은 메모리가 사용되었습니다. 아래의 설명을 참조하십시오.

+2

이 _Exact_ 코드에 메모리 문제가 있습니까? 왜냐하면 나는 TaskManagers 메모리 그래프에서 약간의 충돌을 만들 수 없기 때문이다. –

+0

예 - 정확한 코드입니다. TestEvent에 등록 된 다른 핸들러 나 TestClass의 인스턴스를 만드는 다른 핸들러는 없습니다. Dim TestClass를 1 백만 번하는 간단한 버튼. – stacked

+2

흠 - 재생할 수 없습니다. 다시 테스트하십시오. –

답변

3

처럼으로 VisualStudio은 (_EncList 물건) 편집에 도움을 계속 추가 코드를 생성합니다, 다른 이벤트 처리 패턴을 고려 디버거를 사용하지 않아도됩니다.

"릴리스"로 컴파일 된 프로덕션에서 컴파일하고 실행해야합니다. 그렇습니다. 이렇게하면 메모리 문제가 다르게 동작 할 때 디버깅하기가 어려워 지지만 메모리 문제를 추적하는 것은 어려운 일이 아닙니다.

5

여기에 표시되지 않은 것은 의심 스럽지만 TestClass에서 이벤트가 발생했다는 것입니다. TestEvent에 핸들러를 추가하고있는 중이라면 아마도 제거하지 않을 것입니다. 그것들을 지우지 않으면 GC가 TestClass 나 핸들러의 클래스를 수집하지 못하게한다.

+1

Re : James 컴파일 또는 런타임에 가능한 핸들러를 제외하고 TestEvent에 핸들러를 추가하지 않았습니다. 이 방법으로 생성 된 기본 핸들러를 제외하고 제거가 필요할 것으로 예상되는 것은 없습니다. 귀하의 의견에 구체적으로 보여줄 수있는 .NET 코드에 다른 것이 있습니까? 아니면 실제로 문제가 있다면 런타임에 추가 된 처리기에 액세스 할 수있는 방법이 있습니까? – stacked

+2

James, TestEvent 핸들러는 TestClass에 대한 __outgoing__ 참조이며 GC를 차단하지 않습니다. 인스턴스가 서로 구독하지 않는 한 –

3
  1. GC가 모든 반복에 행동으로 봄하지 않습니다, 그것은 좋은 기회 순간까지 기다렸다가 한꺼번에 이러한 개체를 청소합니다.

  2. TestEvent는 GC에 의한 수집을 차단해서는 안되지만 TestClass의 인스턴스가 다른 객체의 이벤트에 가입하면 살아있을 것입니다. 자동 정리가 없습니다.

  3. "제어 할 수없는 양의 메모리 사용으로 인한 결과"를 어떻게 확인할 수 있습니까? 메모리 사용량 측정은 소리보다 어렵습니다. 나는 이것이 TaskManager를 기반으로하지 않기를 바랍니다.

+0

의견을 보내 주셔서 감사합니다. 지점 3 정보 : 작업 관리자를 기반으로합니다. 내가 작성한이 간단한 응용 프로그램은 훨씬 더 큰 응용 프로그램에서 문제를 골라내는 결과입니다. 메모리 사용량이 증가하면 결국 메모리 부족 예외가 발생합니다. – stacked

+2

@ Stacked- 큰 것에서 다른 사람들이 묘사 한 문제, 특히 사건에 관한 문제가있을 수 있습니다. – RichardOD

+0

RichardOD : "개인 이벤트"행을 주석 처리하면 메모리 사용에 문제가 없습니다. 이것은 더 큰 응용 프로그램과 같은 발생합니다. 내 이벤트에는 핸들러가 없다는 것을 이해하고 있습니다. 이벤트 선언을 주석 처리하면 메모리 사용을 제외한 어떤 방식 으로든 응용 프로그램에 영향을 미치지 않습니다. 이 잘못 이해하고 있습니까? – stacked

5

이 코드는 사용자가 이전에 본 것처럼 누출되지 않습니다. 가비지 컬렉터는 결국 여러분이 만든 클래스를 처리합니다.

Observable 클래스와 Observer 클래스가있는 경우 Observer는 Observable.Event += Observer.EventHandler;을 호출합니다. 이렇게하면 Observable에 Observer에 대한 참조가 다시 생깁니다. Observable.Event -= Observer.EventHandler으로 전화하지 않으면 해당 참조가 계속됩니다.

아무도 Observer에 대한 참조를 가지고 있지 않지만 Observable의 수명이 길다고 생각하면이 문제가 발생합니다. Observable에는 Observer에 대한 참조가 있지만 모든 Handler를 지우지 않는 한 참조를 제거하는 코드는 없습니다 (this.Event = null).

사실상 이것은 메모리 누수입니다!

이 주위에 얻을 수있는 방법은 여러가지 방법이 있습니다 :

  1. 전화 - = 당신은 관찰자를 밖으로 던져 전에.아마도 폐기()
  2. 사용에 Weak Events
  3. 는 디버그에서 실행하는 경우 Event Aggregator
+0

브라이언 감사합니다. "가비지 컬렉터가 결국 여러분이 만든 수업을 처리하게 될 것입니다."언제 "결국"입니까? 이 프로그램을 컴파일하고 실행하면 작업 관리자의 Mem 사용이 통제 불능 상태가되어 다시 회수되지 않습니다. 결국 메모리 부족 예외가 발생합니다. 이것은 GC가 내가 만드는 클래스를 돌보지 않는 것처럼 보일 것입니다. – stacked

관련 문제