.NET에서 메모리 누수를 찾는 데 유용한 전략과 도구는 무엇입니까?


152

나는 10 년 동안 C ++을 썼다. 메모리 문제가 발생했지만 합리적인 노력으로 문제를 해결할 수 있습니다.

지난 몇 년 동안 저는 C #을 작성했습니다. 여전히 많은 메모리 문제가 발생합니다. 비결 정성으로 인해 진단 및 수정이 어렵고 C # 철학은 매우 확실하게 할 때 그러한 일에 대해 걱정할 필요가 없기 때문입니다.

내가 찾은 한 가지 특별한 문제는 코드에서 모든 것을 명시 적으로 처분하고 정리해야한다는 것입니다. 그렇지 않으면 메모리 프로파일 러가 실제로 도움이되지 않습니다. 내가 잘못 생각했는지, 내가 가진 도구가 최고가 아닌지 궁금합니다.

.NET에서 메모리 누수를 해결하는 데 유용한 전략과 도구는 무엇입니까?


게시물 제목이 게시물의 질문과 일치하지 않습니다. 타이틀을 업데이트하는 것이 좋습니다.
Kevin

네가 옳아. 죄송합니다. 현재 사냥중인 누수에 약간의 불만이있었습니다! 제목이 업데이트되었습니다.
Scott Langham

3
@ Scott : .NET에 싫증이 나지 마십시오. 문제가 아닙니다. 귀하의 코드는입니다.
GEOCHET

3
그래, 내 코드 또는 타사 라이브러리를 사용하는 것이 즐겁습니다.
Scott Langham

@ 스콧 : 내 대답을 참조하십시오. MemProfiler는 그만한 가치가 있습니다. 또한이를 사용하면 .NET GC 세계에 대한 완전히 새로운 수준의 이해가 가능합니다.
GEOCHET

답변:


51

메모리 누수가 의심되는 경우 Scitech의 MemProfiler를 사용 합니다.

지금까지는 매우 신뢰할 수 있고 강력하다는 것을 알았습니다. 적어도 한 번은 베이컨을 구했습니다.

GC는 .NET IMO에서 잘 작동하지만 다른 언어 또는 플랫폼과 마찬가지로 나쁜 코드를 작성하면 나쁜 일이 발생합니다.


3
그렇다, 나는 이것과 함께 갔고, 까다로운 누출의 바닥에 도달하는 데 도움이되었다. 내가 가장 큰 누수는 interop을 통해 액세스하는 관리되지 않는 코드의 타사 라이브러리로 인한 것으로 밝혀졌습니다. 이 도구는 관리 코드뿐만 아니라 관리되지 않는 코드에서 누출을 감지 한 것에 깊은 인상을 받았습니다.
Scott Langham

1
나는 이것이 결국 나를 위해 일한 것이기 때문에 대답으로 받아 들였지만 다른 모든 대답은 매우 유용하다고 생각합니다. 그건 그렇고,이 도구는 더 일반적으로 SciTech의 Mem Profiler라고합니다!
Scott Langham

41

잊어 버리기 어려운 문제에 대해서만 이 블로그 게시물에 설명 된 솔루션을 사용해보십시오 . 본질은 다음과 같습니다.

    public void Dispose ()
    {
        // Dispose logic here ...

        // It's a bad error if someone forgets to call Dispose,
        // so in Debug builds, we put a finalizer in to detect
        // the error. If Dispose is called, we suppress the
        // finalizer.
#if DEBUG
        GC.SuppressFinalize(this);
#endif
    }

#if DEBUG
    ~TimedLock()
    {
        // If this finalizer runs, someone somewhere failed to
        // call Dispose, which means we've failed to leave
        // a monitor!
        System.Diagnostics.Debug.Fail("Undisposed lock");
    }
#endif

Debug.Fail 대신 예외를 던지고 싶습니다.
Pedro77

17

우리는 프로젝트에서 Red Gate 소프트웨어의 Ants Profiler Pro 를 사용 했습니다. 모든 .NET 언어 기반 응용 프로그램에서 실제로 잘 작동합니다.

.NET 가비지 콜렉터는 메모리 내 오브젝트를 정리할 때 매우 안전하다는 것을 알았습니다. 우리 는 나중에 언젠가 그것을 사용할 것입니다. 이것은 우리가 메모리에서 부풀린 객체의 수에 대해 더주의를 기울여야한다는 것을 의미했습니다. 결국 메모리 오버 헤드를 줄이고 성능을 향상시키기 위해 모든 데이터 개체를 "주문형 요청"(필드가 요청되기 직전에)으로 변환했습니다.

편집 : 다음은 "요청시 팽창"의 의미에 대한 추가 설명입니다. 데이터베이스의 객체 모델에서 부모 객체의 속성을 사용하여 자식 객체를 노출시킵니다. 예를 들어, 다른 "상세"또는 "조회"레코드를 일대일 기준으로 참조한 레코드가있는 경우 다음과 같이 구성합니다.

class ParentObject
   Private mRelatedObject as New CRelatedObject
   public Readonly property RelatedObject() as CRelatedObject
      get
         mRelatedObject.getWithID(RelatedObjectID)
         return mRelatedObject
      end get
   end property
End class

위의 시스템은 메모리에 많은 레코드가있을 때 실제 메모리와 성능 문제를 일으킨다는 것을 발견했습니다. 그래서 우리는 객체가 요청되었을 때만 팽창하고 필요한 경우에만 데이터베이스 호출이 수행되는 시스템으로 전환했습니다.

class ParentObject
   Private mRelatedObject as CRelatedObject
   Public ReadOnly Property RelatedObject() as CRelatedObject
      Get
         If mRelatedObject is Nothing
            mRelatedObject = New CRelatedObject
         End If
         If mRelatedObject.isEmptyObject
            mRelatedObject.getWithID(RelatedObjectID)
         End If
         return mRelatedObject
      end get
   end Property
end class

개체가 필요할 때까지 메모리에서 유지 되었기 때문에 훨씬 더 효율적인 것으로 나타났습니다 (Get 메서드에 액세스). 데이터베이스 적중을 제한하는 데있어 성능이 크게 향상되었으며 메모리 공간이 크게 향상되었습니다.


나는이 제품을 두 번째입니다. 내가 사용한 최고의 프로파일 러 중 하나였습니다.
Gord

프로파일 러가 성능 문제를 보는 데 매우 유용하다는 것을 알았습니다. 그러나 메모리 분석 도구는 상당히 열악했습니다. 이 도구로 누수가 발견되었지만 누수의 원인을 파악하는 데 도움이되었습니다. 누출이 관리되지 않는 코드로 발생하는 경우 전혀 도움이되지 않습니다.
Scott Langham

Ok, 새로운 버전 5.1은 훨씬 나아졌습니다. 누출의 원인을 찾는 데 도움이됩니다 (하지만 ANTS가 다음 버전에서 수정하겠다고 말한 문제가 여전히 남아 있습니다). 그래도 관리되지 않는 코드는 수행하지 않지만 관리되지 않는 코드에 대해 신경 쓰지 않으면 이것은 매우 좋은 도구입니다.
Scott Langham

7

응용 프로그램이 사소한 것이 아니라면 관리 코드를 작성할 때 메모리에 대해 걱정할 필요가 있습니다. 두 가지를 제안합니다. 먼저 .NET에서 메모리 관리를 이해하는 데 도움이되므로 C #을 통해 CLR을 읽으십시오 . 둘째, CLRProfiler (Microsoft) 와 같은 도구를 사용하는 방법을 배웁니다 . 이것은 당신에게 메모리 누수를 일으키는 원인에 대한 아이디어를 줄 수 있습니다 (예를 들어 큰 객체 힙 조각화를 볼 수 있습니다)


네. CLRPRofiler는 꽤 멋지다. 할당 된 객체를 제공하는보기를 파헤 치려고하면 정보가 약간 폭발 할 수 있지만 모든 것이 있습니다. 특히 무료로 좋은 출발점입니다.
Scott Langham

6

관리되지 않는 코드를 사용하고 있습니까? Microsoft에 따르면 관리되지 않는 코드를 사용하지 않으면 일반적인 의미에서 메모리 누수가 불가능합니다.

그러나 응용 프로그램에서 사용하는 메모리는 해제되지 않을 수 있으므로 응용 프로그램 수명 동안 응용 프로그램의 메모리 할당이 늘어날 수 있습니다.

에서 Microsoft.com에서 공용 언어 런타임에서 메모리 누수를 확인하는 방법

관리되지 않는 코드를 응용 프로그램의 일부로 사용하면 .NET Framework 응용 프로그램에서 메모리 누수가 발생할 수 있습니다. 이 관리되지 않는 코드는 메모리를 누출시킬 수 있으며 .NET Framework 런타임은 해당 문제를 해결할 수 없습니다.

또한 프로젝트에는 메모리 누수가있는 것처럼 보일 수 있습니다. DataTable 개체와 같은 많은 큰 개체를 선언 한 다음 컬렉션 (예 : DataSet)에 추가하면이 조건이 발생할 수 있습니다. 이러한 개체가 소유 한 리소스는 절대 해제 될 수 없으며 전체 프로그램 실행 동안 리소스가 유지됩니다. 이것은 누출로 보이지만 실제로는 프로그램에서 메모리가 할당되는 방식의 증상 일뿐입니다.

이 유형의 문제를 처리하기 위해 IDisposable 을 구현할 수 있습니다 . 메모리 관리를 다루는 몇 가지 전략을 보려면 IDisposable, XNA, 메모리 관리를 검색하는 것이 좋습니다. 게임 개발자가 더 예측 가능한 가비지 수집이 필요하므로 GC가 강제로 수행해야하므로 를 .

한 가지 일반적인 실수는 객체를 구독하는 이벤트 핸들러를 제거하지 않는 것입니다. 이벤트 핸들러 구독은 오브젝트가 재활용되지 않도록합니다. 또한 리소스 수명 동안 제한된 범위를 만들 수 있는 using 문을 살펴보십시오 .


5
blogs.msdn.com/tess/archive/2006/01/23/…를 참조하십시오 . 메모리 누수가 "전통적인"것인지 아닌지는 중요하지 않지만 여전히 누수입니다.
콘스탄틴

2
요점을 알지만 프로그램에 의한 비효율적 인 메모리 할당 및 재사용은 메모리 누수와 다릅니다.
Timothy Lee Russell

좋은 답변입니다. 이벤트 핸들러가 위험 할 수 있음을 기억해 주셔서 감사합니다.
frameworkninja

3
@ 티모시 리 러셀 (Timothy Lee Russel) : 시스템에 아무런 정보도없고 적시에 루트를 푸는 데 필요한 자극이없는 상태에서 무한한 (1) 메모리 양이 동시에 할당 (루트) 된 상태로 남아있을 수있는 경우 (2), 메모리 누수 . 언젠가는 메모리가 해제 될 수 있지만, 쓸모없는 것들이 시스템을 질식시키기 전에 축적 될 수 있다면 누수가됩니다. (1) O (N)보다 크며, N은 유용한 할당량이다. (2) 참조를 제거해도 프로그램 기능에 영향을 미치지 않으면 물건은 쓸모가 없습니다.
supercat

2
@ 티모시 리 러셀 (Timothy Lee Russel) : 일반적인 "메모리 누수"패턴은 메모리가 다른 개체를 대신하여 한 개체 의해 유지 될 때 발생 하며 더 이상 필요하지 않을 때 알려지기를 기대하지만 후자는 첫 번째 개체를 알리지 않고 개체를 버립니다. 메모리를 보유한 실체는 실제로 필요하지 않지만 그것을 결정할 방법은 없습니다.
supercat

5

이 블로그 에는 windbg 및 기타 도구를 사용하여 모든 유형의 메모리 누수를 추적하는 훌륭한 연습이 있습니다. 실력을 향상시키기위한 독해력.


5

방금 Windows 서비스에서 메모리 누수가 발생하여 수정했습니다.

먼저 MemProfiler를 사용해 보았습니다. . 나는 사용하기가 어렵고 전혀 사용자 친화적이지 않다는 것을 알았습니다.

그런 다음 JustTrace를 사용 했습니다. 하기 쉽고 를 사용하여 올바르게 배치되지 않은 객체에 대한 자세한 정보를 제공합니다.

메모리 누수를 정말 쉽게 해결할 수있었습니다.


3

관찰하고있는 누수가 런 어웨이 캐시 구현으로 인한 것이라면 이것이 시나리오 일 수 있습니다. WeakReference의 사용을 고려할 입니다. 이렇게하면 필요할 때 메모리가 해제되도록 할 수 있습니다.

그러나 IMHO는 맞춤형 솔루션을 고려하는 것이 좋습니다. 객체를 얼마나 오래 유지해야 하는지를 아는 사람 만 있으므로 상황에 맞는 적절한 하우스 키핑 코드를 설계하는 것이 가장 좋습니다.


3

나는 Jetbrains의 dotmemory 를 선호합니다


당신은 유일한 사람이 될 수 있습니다 :)
HellBaby

나도 시도했다. 나는 이것이 좋은 도구라고 생각한다. 사용하기 쉽고 유익합니다. Visual Studio와 통합
redeye

이 경우 메모리 누수 문제를 해결할 때 Visual Studio Snapshot 도구가 충돌 / 스냅 샷되지 않았습니다. Dotmemory는 시원하게 유지되었으며 3 개 이상의 GB의 여러 스냅 샷을 쉽게 볼 수있었습니다.
Michael Kargl

3

큰 총 -Windows 용 디버깅 도구

이것은 놀라운 도구 모음입니다. 관리되는 힙과 관리되지 않는 힙을 모두 분석하여 오프라인으로 수행 할 수 있습니다. 메모리 과다 사용으로 인해 재활용을 유지 한 ASP.NET 응용 프로그램 중 하나를 디버깅하는 데 매우 유용했습니다. 프로덕션 서버에서 실행중인 리빙 프로세스의 전체 메모리 덤프 만 작성해야했으며 모든 분석은 WinDbg에서 오프라인으로 수행되었습니다. (일부 개발자는 인 메모리 세션 스토리지를 과도하게 사용하고있었습니다.)

"깨진 경우는 ..." 블로그는 주제에 매우 유용한 기사가있다.


2

명심해야 할 가장 좋은 점은 객체에 대한 참조를 추적하는 것입니다. 더 이상 신경 쓰지 않는 객체에 대한 참조를 매달면 매우 쉽습니다. 더 이상 사용하지 않으려면 제거하십시오.

슬라이딩 만료가있는 캐시 공급자를 사용하는 데 익숙해 지므로 원하는 시간 동안 무언가를 참조하지 않으면 역 참조되고 정리됩니다. 그러나 많이 액세스하면 메모리에 표시됩니다.


2

가장 좋은 도구 중 하나는 Windows 용 디버깅 도구를 사용하고 adplus 를 사용 하여 프로세스의 메모리 덤프를 가져온 다음 windbgsos 플러그인을 사용하여 프로세스 메모리, 스레드 및 호출 스택을 분석하는 것입니다.

도구를 설치 한 후이 방법을 사용하여 서버에서 문제점을 식별하고 디렉토리를 공유 한 다음 (순 사용)을 사용하여 서버에서 공유에 연결하고 프로세스의 충돌 또는 정지 덤프를 수행 할 수 있습니다.

그런 다음 오프라인을 분석하십시오.


예, 이것은 디버거를 쉽게 연결할 수없는 출시 된 소프트웨어의 고급 기능이나 진단 문제에 특히 효과적입니다. :이 블로그는 잘 이러한 도구를 사용하는 방법에 대한 팁을 많이 가지고 blogs.msdn.com/tess
스콧 랭함

2

관리되는 응용 프로그램에 대한 수정 프로그램 중 하나를 수행 한 후 다음 변경 후 응용 프로그램에서 동일한 메모리 누수가 발생하지 않는지 확인하는 방법과 같은 내용이 있었으므로 Object Release Verification 프레임 워크와 같은 것을 작성했습니다. NuGet 패키지 ObjectReleaseVerification . https://github.com/outcoldman/OutcoldSolutions-ObjectReleaseVerification-Sample 샘플 및이 샘플에 대한 정보는 http://outcoldman.ru/en/blog/show/322 에서 찾을 수 있습니다.


0

Visual Studio 2015에서 즉시 사용 가능한 메모리 사용 진단 도구 를 사용하여 메모리 사용 데이터를 수집하고 분석하는 것이 좋습니다.

메모리 사용 도구를 사용하면 개체 유형의 메모리 사용에 대한 영향을 이해하는 데 도움이되는 관리 및 기본 메모리 힙의 스냅 샷을 하나 이상 만들 수 있습니다.


0

내가 DotMemory를 사용한 최고의 도구 중 하나입니다.이 도구를 VS.의 확장으로 사용할 수 있습니다. , 다른 SnapShot과 비교하십시오. DotMemory

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.