2017-09-29 2 views
0

우리는 수백 개의 클라이언트에 WinForms 응용 프로그램을 설치했습니다. 일부에서는 OutOfMemoryException이 결국 throw 될 때까지 메모리 사용이 명백한 이유없이 시간이 지남에 따라 올라 가기 시작합니다.Finalizer 스레드 오작동으로 인한 메모리 누수 문제 해결

우리는 DebugDiag Collection and Analysis를 사용하여 문제를 이해하려고했습니다. 우리는 these warnings을 얻었습니다.

마무리 작업을위한 거대한 대기열 개체 (42K)가 있었기 때문에 처음에는 Finalizer 스레드를 살펴 보았습니다.

ntdll!KiFastSystemCallRet 
ntdll!NtWaitForSingleObject+c 
KERNELBASE!WaitForSingleObjectEx+98 
kernel32!WaitForSingleObjectExImplementation+75 
clr!CLREventBase::Reset+17e 
clr!CLREventBase::Reset+1c6 
clr!CLREventBase::WaitEx+152 
clr!FinalizerThread::WaitForFinalizerEvent+38 
clr!FinalizerThread::FinalizerThreadWorker+5f 
clr!Thread::DoExtraWorkForFinalizer+1b1 
clr!Thread::DoExtraWorkForFinalizer+234 
clr!Thread::DoExtraWorkForFinalizer+5f8 
[[DebuggerU2MCatchHandlerFrame]] 
clr!ManagedThreadBase::FinalizerBase+33 
clr!FinalizerThread::FinalizerThreadStart+d4 
clr!Thread::intermediateThreadProc+55 
kernel32!BaseThreadInitThunk+e 
ntdll!__RtlUserThreadStart+70 
ntdll!_RtlUserThreadStart+1b 

같은 과정을 다섯 시간 후에, 그리고 DebugDiag에 의해 표시되는 경고 these 같습니다이는 호출 스택 덤프시처럼 보였다 방법이다.

그래서, 마무리 작업 준비가 완료되면 메모리가 거의 두 배로 누출되었습니다. Finalizer 스레드 호출 스택은 이전 스레드 호출 스택과 동일합니다. 사실, 문제는 차단 된 최종 스레드에있는 것처럼 보이므로 GC가 사용되지 않는 객체를 제거 할 수 없습니다.

우리는 코드에 파이널 라이저를 사용하지 않습니다. 파이널 라이저 스레드가 수행 할 블로킹 작업은 무엇입니까? 어떻게 책임질 수있는 외부 모듈이 있는지, 그리고 어떤 모듈이 있는지 알아낼 수 있습니까?

몇 가지 추가 정보 : 우리는 .NET Framework 4.0을 사용 중이며 우리의 응용 프로그램은 x86 용으로 컴파일됩니다. 이 문제는 Windows 7+ SO에서 재현 될 가능성이 높지만 XP는 더 잘 작동하는 것처럼 보입니다.

어디서 볼지에 대한 도움이나 힌트를 주시면 감사하겠습니다.

+0

꽤 높지만 finalizer 스레드 스택 추적은 완전히 정상입니다. 사용되는 메모리의 양이 너무 많아서 메모리가 부족한 프로그램이 아닙니다. GC가 자주 실행되는지 확인하십시오. –

+0

우리는 약 5 시간의 실행을 말합니다. 우리의 응용 프로그램은 다시 시작하지 않고 몇 달 동안 작동 할 것으로 예상되며, 그 때 OutOfMemory가 발생합니다. – armarru

답변

1

가치가있는 것 : 몇 년 전에 필자는 비슷한 상황이었습니다. gdi 오류는 프로그램에서 자원이 부족한 경우에 발생합니다. 마침내 나는 많은 물건들이 기억 속에 남아 있음을 발견하기 위해 redgate의 개미 (무료 체험 기간)를 사용했다. 나는 VB.NET을 사용했으며, 'withevents'로 선언 된 변수는 finalizer에서 명시 적으로 설정 될 필요가없는 것으로 알려져 있습니다. 또한 다른 객체에 대한 참조를 전달하고 유지하는 것은 쓰레기 수거자가 왜 오지 않는지에 대한 잠재적 인 이유입니다. 이러한 참조를 finalizer의 nothing (null)으로 설정하면 도움이됩니다. VB에서 폼의 finalizer 코드는 디자이너 파일에 있습니다.

'Form overrides dispose to clean up the component list. 
    <System.Diagnostics.DebuggerNonUserCode()> _ 
    Protected Overrides Sub Dispose(ByVal disposing As Boolean) 
     If disposing AndAlso components IsNot Nothing Then 
      components.Dispose() 
     End If 

     MyBase.Dispose(disposing) 
     If Me.DesignMode Then Exit Sub 

     If disposing Then 
      JCboKind.DataSource = Nothing 
      JCBOCondition.DataSource = Nothing 
      JCboQuality.DataSource = Nothing 
      JCboSafetyCategory.DataSource = Nothing 
      JcboSurfTreatment.DataSource = Nothing 
      JCboUnit.DataSource = Nothing 
     End If 
     ... 
+0

우리는 또한 VB.NET을 사용하고 있으며 실제로 가능한 원인처럼 들릴 수 있습니다. 우리는 그것을 조사 할 것이다. – armarru

+0

내가 할 수있는 곳마다, 'Using ... End Using'구조 (IDisposable을 구현하는 모든 객체), 즉 대화 상자, sqlconnections, sqlcommands, filestreams ...을 사용합니다. –