문제

.NET에서 메모리 누수가 발생할 수 있는 가능한 방법은 무엇입니까?

나는 두 가지를 알고 있습니다:

  1. 등록이 제대로 취소되지 않음 이벤트 핸들러/대리자.
  2. Windows Forms에서 동적 하위 컨트롤을 삭제하지 않음:

예:

// Causes Leaks  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  

// Correct Code  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  
label.Dispose();

업데이트:아이디어는 (위와 같이) 너무 명확하지 않은 일반적인 함정을 나열하는 것입니다.일반적으로 가비지 수집기 때문에 메모리 누수는 큰 문제가 되지 않는다는 개념이 있습니다.C++에서와는 다릅니다.


훌륭한 토론입니다. 하지만 명확히하겠습니다 ...정의에 따르면 .NET의 개체에 대한 참조가 남아 있지 않으면 언젠가는 가비지 수집됩니다.따라서 이는 메모리 누수를 유발하는 방법이 아닙니다.

관리되는 환경에서 알지 못하는 개체에 대한 의도하지 않은 참조가 있는 경우 메모리 누수로 간주합니다(따라서 내 질문의 두 가지 예).

그렇다면 이러한 메모리 누수가 발생할 수 있는 다양한 방법은 무엇입니까?

도움이 되었습니까?

해결책

종료자 스레드를 차단합니다.종료자 스레드가 차단 해제될 때까지 다른 객체는 가비지 수집되지 않습니다.따라서 사용되는 메모리의 양은 계속해서 증가합니다.

추가 자료: http://dotnetdebug.net/2005/06/22/blocked-finalizer-thread/

다른 팁

실제로 누출이 발생하지는 않으며 GC에 더 많은 작업을 수행할 뿐입니다.

// slows GC
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  

// better  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  
label.Dispose();

// best
using( Label label = new Label() )
{ 
    this.Controls.Add(label);  
    this.Controls.Remove(label);  
}

일회용 구성 요소를 이렇게 방치해 두는 것은 .Net과 같은 관리 환경에서는 결코 큰 문제가 되지 않습니다. 이는 관리의 의미에서 큰 부분을 차지합니다.

확실히 앱 속도가 느려질 것입니다.그러나 당신은 다른 것을 위해 혼란을 남기지 않을 것입니다.

설정 GridControl.DataSource BindingSource 클래스의 인스턴스를 사용하지 않고 속성을 직접 사용합니다(http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx).

이로 인해 프로파일러를 사용하여 추적하는 데 꽤 오랜 시간이 걸리는 응용 프로그램 누출이 발생했으며 결국 Microsoft가 응답한 다음 버그 보고서를 발견했습니다. http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=92260

BindingSource 클래스에 대한 문서에서 Microsoft가 이를 합법적인 클래스로 전달하려고 시도하는 것은 재밌지만 통화 관리자 및 그리드 컨트롤에 데이터 바인딩과 관련된 근본적인 누출을 해결하기 위해 이 클래스를 만든 것 같습니다.

이 점을 조심하세요. 이로 인해 누출되는 응용 프로그램이 절대적으로 많이 있을 것입니다!

포괄적인 목록을 제공할 방법이 없습니다...이것은 "어떻게 젖을 수 있나요?"라고 묻는 것과 매우 흡사합니다.

즉, IDisposable을 구현하는 모든 항목에 대해 Dispose()를 호출하고 모든 종류의 관리되지 않는 리소스를 사용하는 모든 유형에 대해 IDisposable을 구현하는지 확인하세요.

때때로 해당 규칙을 적용하는 데 도움이 되도록 코드베이스에서 FxCop과 같은 것을 실행하십시오. 일부 일회용 개체가 애플리케이션 프레임워크 내에 얼마나 깊이 묻혀 있는지 놀라게 될 것입니다.

관리되지 않는 리소스가 올바르게 삭제되지 않도록 하는 Finalize(또는 Finaliser의 Dispose 호출) 메서드의 예외입니다.일반적인 것은 프로그래머 때문입니다. 가정 어떤 순서 개체가 삭제될지, 이미 삭제된 피어 개체를 해제하려고 하면 예외가 발생하고 나머지 Finalise/Dispose from Finalize 메서드가 호출되지 않습니다.

이 토론에 추가할 항목이 4개 있습니다:

  1. 이러한 이벤트에 대한 적절한 준비 없이 UI 컨트롤을 생성한 스레드(Thread.Abort())를 종료하면 메모리가 예상대로 사용될 수 있습니다.

  2. Pinvoke를 통해 관리되지 않는 리소스에 액세스하고 정리하지 않으면 메모리 누수가 발생할 수 있습니다.

  3. 큰 문자열 개체 수정.반드시 메모리 누수일 필요는 없습니다. 일단 범위를 벗어나면 GC가 이를 처리합니다. 그러나 성능 측면에서 큰 문자열이 자주 수정되면 시스템이 타격을 입을 수 있습니다. 프로그램의 공간을 보장하기 위해 GC에 실제로 의존할 수 없기 때문입니다. 최소한.

  4. 사용자 지정 그리기를 수행하기 위해 GDI 개체를 자주 생성합니다.GDI 작업을 자주 수행하는 경우 단일 gdi 개체를 재사용하세요.

매번 IDisposable을 호출하는 것은 시작하기 가장 쉬운 곳이며 확실히 코드 베이스에서 모든 낮은 메모리 누수 문제를 파악하는 효과적인 방법입니다.그러나 항상 충분하지는 않습니다.예를 들어 런타임 시 관리 코드가 생성되는 방법과 시기를 이해하고 어셈블리가 애플리케이션 도메인에 로드되면 언로드되지 않으므로 애플리케이션 공간이 늘어날 수 있다는 점을 이해하는 것도 중요합니다.

.NET 메모리 누수를 방지하려면:

1) 'IDisposable' 인터페이스가 있는 개체가 생성될 때마다 'using' 구문(또는 'try-finally 구문)을 사용합니다.

2) 스레드를 생성하거나 정적 또는 장기 컬렉션에 개체를 추가하는 경우 클래스를 'IDisposable'로 만듭니다.C# '이벤트'는 컬렉션이라는 점을 기억하세요.

여기에 대한 짧은 기사가 있습니다. 메모리 누수 방지 팁.

예상치 못한 메모리 사용량이나 실제 누수에 대해 이야기하고 있습니까?귀하가 나열한 두 가지 사례는 정확히 유출이 아닙니다.물체가 의도한 것보다 오래 붙어 있는 경우입니다.

즉, 메모리 누수라고 부르는 사람이 몰랐거나 잊어버린 참고 자료입니다.

편집하다:또는 가비지 수집기나 비관리 코드의 실제 버그입니다.

편집 2:이에 대해 생각하는 또 다른 방법은 항상 개체에 대한 외부 참조가 적절하게 해제되는지 확인하는 것입니다.외부는 통제할 수 없는 코드를 의미합니다.그런 일이 발생하는 경우는 메모리가 "누수"될 수 있는 경우입니다.

  1. 더 이상 필요하지 않은 객체에 대한 참조를 유지합니다.

다른 의견에 대해 - Dispose가 호출되도록 하는 한 가지 방법은 다음을 사용하는 것입니다.코드 구조가 허용하는 경우.

나에게 정말 예상치 못한 한 가지는 다음과 같습니다.

Region oldClip = graphics.Clip;
using (Region newClip = new Region(...))
{
    graphics.Clip = newClip;
    // draw something
    graphics.Clip = oldClip;
}

메모리 누수는 어디에 있습니까?응, 처분했어야지 oldClip, 도!왜냐하면 Graphics.Clip getter가 호출될 때마다 새로운 일회용 개체를 반환하는 드문 속성 중 하나입니다.

Tess Fernandez는 메모리 누수 찾기 및 디버깅에 대한 훌륭한 블로그 게시물을 보유하고 있습니다.실습 6 연구실 7

관리되지 않는 언어에서 메모리 누수를 일으킬 수 있는 많은 것들이 관리되는 언어에서도 메모리 누수를 일으킬 수 있습니다.예를 들어, 잘못된 캐싱 정책 메모리 누수가 발생할 수 있습니다.

그러나 Greg와 Danny가 말했듯이 포괄적인 목록은 없습니다.유효 수명 이후에 메모리를 보유하게 될 수 있는 모든 것은 누출을 일으킬 수 있습니다.

교착 상태 스레드는 절대로 루트를 해제하지 않습니다.분명히 교착 상태가 더 큰 문제를 가져온다고 주장할 수 있습니다.

교착 상태의 종료자 스레드는 남아 있는 모든 종료자가 실행되는 것을 방지하고 따라서 종료 가능한 모든 개체가 회수되는 것을 방지합니다(그들은 여전히 ​​연결 가능한 목록에 의해 루트되고 있기 때문입니다).

다중 CPU 시스템에서는 종료자 스레드가 종료자를 실행할 수 있는 것보다 더 빠르게 종료 가능한 개체를 생성할 수 있습니다.이것이 지속되는 한 메모리가 "누출"됩니다.이런 일이 야생에서 일어날 가능성은 거의 없지만 재현하기는 쉽습니다.

대형 개체 힙은 압축되지 않으므로 조각화로 인해 메모리가 누수될 수 있습니다.

수동으로 해제해야 하는 개체가 많이 있습니다.예:임대 및 어셈블리가 없는 원격 개체(AppDomain을 언로드해야 함)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top