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

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

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

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

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



답변

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

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

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


답변

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

    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


답변

우리는 프로젝트에서 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 메서드에 액세스). 데이터베이스 적중을 제한하는 데있어 성능이 크게 향상되었으며 메모리 공간이 크게 향상되었습니다.


답변

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


답변

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

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

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

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

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

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

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


답변

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


답변

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

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

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

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