IDisposable 인터페이스의 올바른 사용

인터페이스 의 “기본”사용은 관리되지 않는 리소스를 정리하는 것이라고 Microsoft 설명서 를 읽은 것으로 알고 IDisposable있습니다.

나에게 “관리되지 않는”은 데이터베이스 연결, 소켓, 창 핸들 등과 같은 것을 의미합니다. 그러나 가비지 수집기가 처리해야하기 때문에 관리 리소스 Dispose()를 해제하기 위해 메서드가 구현되는 코드를 보았습니다. 당신을 위해.

예를 들면 다음과 같습니다.

public class MyCollection : IDisposable
{
    private List<String> _theList = new List<String>();
    private Dictionary<String, Point> _theDict = new Dictionary<String, Point>();

    // Die, clear it up! (free unmanaged resources)
    public void Dispose()
    {
        _theList.clear();
        _theDict.clear();
        _theList = null;
        _theDict = null;
    }

내 질문은, 이것이 가비지 수집기에서 사용하는 메모리를 MyCollection평소보다 빠르게 사용 합니까?

편집 : 지금까지 사람들은 데이터베이스 연결 및 비트 맵과 같은 관리되지 않는 리소스를 정리하기 위해 IDisposable을 사용하는 좋은 예를 게시했습니다. 그러나 _theList위의 코드에 백만 개의 문자열이 포함되어 있고 가비지 수집기를 기다리는 대신 지금 해당 메모리를 비우기를 원한다고 가정하십시오 . 위의 코드가 그것을 달성 할 것입니까?



답변

폐기의 포인트 입니다 관리되지 않는 리소스를 해제 할 수 있습니다. 특정 시점에 수행해야합니다. 그렇지 않으면 정리되지 않습니다. 가비지 컬렉터가 모르는 방법 전화 DeleteHandle()유형의 변수에 IntPtr, 그것은 모르는 여부 가 호출 할 필요 여부 DeleteHandle().

참고 : 관리되지 않는 리소스 란 무엇입니까 ? Microsoft .NET Framework에서 찾은 경우 관리됩니다. MSDN을 직접 둘러 보았다면 관리되지 않습니다. P / Invoke 호출을 사용하여 .NET Framework에서 사용할 수있는 모든 것의 편안한 세상을 벗어나는 것은 관리되지 않으며 이제는이를 정리해야합니다.

당신의 요구를 만든 것을 목적은 노출하는 일부 외부 세계가 관리되지 않는 리소스를 정리하기 위해 호출 할 수있는, 방법. 이 방법의 이름은 원하는대로 지정할 수 있습니다.

public void Cleanup()

또는

public void Shutdown()

그러나 대신이 방법에 대한 표준화 된 이름이 있습니다.

public void Dispose()

심지어 IDisposable하나의 메소드를 가진 인터페이스가 생성되었습니다 .

public interface IDisposable
{
   void Dispose()
}

따라서 객체가 IDisposable인터페이스를 노출하게 만들고 관리되지 않는 리소스를 정리하는 단일 방법을 작성했다고 약속합니다.

public void Dispose()
{
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
}

그리고 당신은 끝났습니다. 더 잘할 수 있다면 말고


객체가 250MB의 System.Drawing.Bitmap (즉, .NET 관리 비트 맵 클래스)을 일종의 프레임 버퍼로 할당 한 경우 어떻게 됩니까? 물론 이것은 관리되는 .NET 객체이며 가비지 수집기는이를 해제합니다. 그러나 250MB의 메모리를 그대로두고 싶 습니까? 가비지 수집기가 결국 와서 해제 할 때까지 기다리 십니까? 열린 데이터베이스 연결 이 있으면 어떻게 됩니까? 확실히 우리는 GC가 객체를 마무리하기를 기다리면서 연결이 열려있는 것을 원하지 않습니다.

사용자가 Dispose()(더 이상 객체를 사용할 계획이 없음을 의미) 호출 한 경우 낭비되는 비트 맵과 데이터베이스 연결을 제거하지 않는 이유는 무엇입니까?

이제 우리는 :

  • 관리되지 않는 리소스를 제거해야합니다 (필수로 인해).
  • 도움이되기를 원하기 때문에 관리 자원 제거

Dispose()관리 객체를 제거하기 위해 메소드를 업데이트 해 봅시다 :

public void Dispose()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //Free managed resources too
   if (this.databaseConnection != null)
   {
      this.databaseConnection.Dispose();
      this.databaseConnection = null;
   }
   if (this.frameBufferImage != null)
   {
      this.frameBufferImage.Dispose();
      this.frameBufferImage = null;
   }
}

그리고 당신이 더 잘할 수 있다는 것을 제외하고 는 모든 것이 좋습니다 !


사람이 물건 을 부르는 것을 잊어 버린 경우 어떻게해야 Dispose()합니까? 그러면 관리되지 않는 리소스 가 누출 될 것입니다 !

참고 : 결국 가비지 수집기가 백그라운드 스레드에서 실행되고 사용되지 않는 개체와 관련된 메모리를 해제하기 때문에 관리되는 리소스가 누출되지 않습니다 . 여기에는 개체 및 사용하는 모든 관리되는 개체 (예 : BitmapDbConnection)가 포함됩니다.

사람이 전화를 잊어 버린 경우 에도 베이컨을 저장할 Dispose()있습니다 ! 가비지 수집기가 마침내 객체를 해제 (즉, 마무리) 할 때까지이를 호출 할 있습니다.

참고 : 가비지 수집기는 결국 모든 관리 대상 개체를 해제합니다. 그렇게되면 Finalize
객체 에서 메소드를 호출 합니다. GC의 알다시피, 나에 대한 배려하지 않는 당신의 폐기 방법. 그것은 우리가 관리되지 않는 것들을 제거하고 싶을 때 호출하는 방법으로 선택한 이름입니다.

가비지 콜렉터가 오브젝트를 파괴 하는 것은 성가신 관리되지 않는 자원을 자유롭게하기 위한 완벽한 시간입니다. 우리는 방법을 재정 의하여이 작업을 수행합니다 Finalize().

참고 : C #에서는 Finalize()메서드를 명시 적으로 재정의하지 않습니다 . 당신이하는 방법을 쓰기 같은 외모 C ++ 소멸자 및 컴파일러의 구현으로 그 소요 Finalize()방법 :

~MyObject()
{
    //we're being finalized (i.e. destroyed), call Dispose in case the user forgot to
    Dispose(); //<--Warning: subtle bug! Keep reading!
}

그러나 해당 코드에 버그가 있습니다. 가비지 수집기는 백그라운드 스레드 에서 실행됩니다 . 당신은 두 물체가 파괴되는 순서를 모른다. 당신에 전적으로 가능하다 Dispose()코드의 관리 당신이하려는 개체가 (당신이 도움이 될 싶었 기 때문에) 더 이상 존재하지 없애 :

public void Dispose()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.gdiCursorBitmapStreamFileHandle);

   //Free managed resources too
   if (this.databaseConnection != null)
   {
      this.databaseConnection.Dispose(); //<-- crash, GC already destroyed it
      this.databaseConnection = null;
   }
   if (this.frameBufferImage != null)
   {
      this.frameBufferImage.Dispose(); //<-- crash, GC already destroyed it
      this.frameBufferImage = null;
   }
}

따라서 관리 대상 리소스를 더 이상 사용 하지 않을 수 있으므로 관리 리소스를 건드리지 말고 관리되지 않는 리소스를 계속 확보 해야한다는 것을 Finalize()수 있습니다 .Dispose()

이 작업을 수행하는 표준 패턴을 가지고있다 Finalize()그리고 Dispose()모두 전화 발신 제 3 (!) 방법; 여기서 불리언 말을 전달하는 경우 Dispose()(와 반대로 Finalize()), 관리되는 리소스를 해제하는 것이 안전하다는 의미입니다.

내부 메소드에는 “CoreDispose”또는 “MyInternalDispose”와 같은 임의의 이름이 지정 수 있지만이를 호출하는 것이 일반적입니다 Dispose(Boolean).

protected void Dispose(Boolean disposing)

그러나 더 유용한 매개 변수 이름은 다음과 같습니다.

protected void Dispose(Boolean itIsSafeToAlsoFreeManagedObjects)
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //Free managed resources too, but only if I'm being called from Dispose
   //(If I'm being called from Finalize then the objects might not exist
   //anymore
   if (itIsSafeToAlsoFreeManagedObjects)  
   {    
      if (this.databaseConnection != null)
      {
         this.databaseConnection.Dispose();
         this.databaseConnection = null;
      }
      if (this.frameBufferImage != null)
      {
         this.frameBufferImage.Dispose();
         this.frameBufferImage = null;
      }
   }
}

그리고 IDisposable.Dispose()메소드 구현을 다음과 같이 변경하십시오 .

public void Dispose()
{
   Dispose(true); //I am calling you from Dispose, it's safe
}

그리고 당신의 파이널 라이저는 :

~MyObject()
{
   Dispose(false); //I am *not* calling you from Dispose, it's *not* safe
}

참고 : 객체가을 구현하는 객체의 자손 인 경우 Dispose를 재정의 할 때 기본 Dispose 메서드 Dispose를 호출하는 것을 잊지 마십시오.

public override void Dispose()
{
    try
    {
        Dispose(true); //true: safe to free managed resources
    }
    finally
    {
        base.Dispose();
    }
}

그리고 당신이 더 잘할 수 있다는 것을 제외하고 는 모든 것이 좋습니다 !


사용자가 Dispose()개체를 호출하면 모든 것이 정리 된 것입니다. 나중에 가비지 수집기가 와서 Finalize를 호출하면 Dispose다시 호출 됩니다.

이 방법은 낭비 일뿐만 아니라 객체에 마지막 호출 에서 이미 폐기 한 객체에 대한 정크 참조가있는 경우 해당 객체를 Dispose()다시 처리하려고합니다.

내 코드에서 내가 처리 한 객체에 대한 참조를 제거하는 데주의를 기울 였으므로 Dispose정크 객체 참조 를 호출하지 않습니다 . 그러나 그것은 미묘한 버그가 들어 오는 것을 막지 못했습니다.

사용자가 호출하면 Dispose(): 핸들 CursorFileBitmapIconServiceHandle 이 삭제됩니다. 나중에 가비지 수집기가 실행되면 동일한 핸들을 다시 파괴하려고 시도합니다.

protected void Dispose(Boolean iAmBeingCalledFromDisposeAndNotFinalize)
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle); //<--double destroy 
   ...
}

이 문제를 해결하는 방법은 가비지 수집기에 개체를 마무리 할 필요가 없음을 알리는 것입니다. 리소스가 이미 정리되었으며 더 이상 작업이 필요하지 않습니다. 메소드 를 호출 GC.SuppressFinalize()하여 이를 수행하십시오 Dispose().

public void Dispose()
{
   Dispose(true); //I am calling you from Dispose, it's safe
   GC.SuppressFinalize(this); //Hey, GC: don't bother calling finalize later
}

사용자가을 호출 Dispose()했으므로

  • 관리되지 않는 리소스 해제
  • 해제 된 관리 자원

GC에는 파이널 라이저를 실행하는 것이 중요하지 않습니다. 모든 것이 처리됩니다.

관리되지 않는 리소스를 정리하기 위해 Finalize를 사용할 수 없습니까?

에 대한 설명서 Object.Finalize는 다음과 같습니다.

Finalize 메서드는 개체가 삭제되기 전에 현재 개체가 보유한 관리되지 않는 리소스에 대해 정리 작업을 수행하는 데 사용됩니다.

그러나 MSDN 설명서에서도 다음과 같이 말합니다 IDisposable.Dispose.

관리되지 않는 리소스 해제, 해제 또는 재설정과 관련된 응용 프로그램 정의 작업을 수행합니다.

그래서 어느 것입니까? 관리되지 않는 리소스를 정리할 수있는 곳은 어디입니까? 정답은:

당신의 선택입니다! 그러나를 선택하십시오 Dispose.

마무리되지 않은 정리는 마무리 도구에 넣을 수 있습니다.

~MyObject()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //A C# destructor automatically calls the destructor of its base class.
}

문제는 가비지 수집기가 언제 객체를 마무리할지 알 수 없다는 것입니다. 가비지 수집기 실행될 때까지 관리되지 않고 필요하지 않은 사용하지 않은 기본 리소스가 계속 사용 됩니다. 그런 다음 finalizer 메서드를 호출합니다. 관리되지 않는 리소스 정리 Object.Finalize 의 문서는 이것을 지적합니다.

종료자가 실행되는 정확한 시간은 정의되어 있지 않습니다. 클래스 인스턴스에 대한 결정적인 자원 릴리스를 보장하려면 Close 메소드를 IDisposable.Dispose구현 하거나 구현을 제공하십시오 .

이것은 Dispose관리되지 않는 리소스를 정리 하는 데 사용하는 장점입니다 . 관리되지 않는 리소스가 정리되면이를 파악하고 제어 할 수 있습니다. 그들의 파괴는 “결정 론적” 이다.


원래의 질문에 대답하기 위해 : GC가 메모리를 결정할 때가 아니라 지금 메모리를 해제하지 않는 이유는 무엇입니까? 나는 그 얼굴 인식 소프트웨어가없는 요구가 내부 이미지의 530메가바이트 제거하는 지금이 더 이상 필요 것 때문에. 그렇지 않은 경우 : 기계가 교환 정지로 분쇄됩니다.

보너스 독서

이 답변의 스타일 (설명하는이 좋아하는 사람들을위한 이유 (가) 그래서 방법을 분명하게), 당신이 돈 상자의 필수 COM의 장 하나를 읽어 제안을 :

35 페이지에서 그는 이진 객체 사용의 문제점을 설명하고 COM을 당신의 눈앞에서 발명합니다. COM 의 이유 를 알고 나면 나머지 300 페이지는 분명하며 Microsoft의 구현에 대해 자세히 설명합니다.

객체 나 COM을 다루는 모든 프로그래머는 최소한 첫 번째 장을 읽어야한다고 생각합니다. 그것은 무엇이든에 대한 최고의 설명입니다.

추가 보너스 독서

Eric Lippert 가 아는 모든 것이 잘못되었을 때

따라서 올바른 종료자를 작성하는 것은 실제로 매우 어렵습니다. 제가 드릴 수있는 최선의 조언은 시도하지 않는 것 입니다.


답변

IDisposableusing문 을 활용하고 관리 대상 개체를 결정적으로 정리하는 쉬운 방법 을 활용하는 데 종종 사용됩니다 .

public class LoggingContext : IDisposable {
    public Finicky(string name) {
        Log.Write("Entering Log Context {0}", name);
        Log.Indent();
    }
    public void Dispose() {
        Log.Outdent();
    }

    public static void Main() {
        Log.Write("Some initial stuff.");
        try {
            using(new LoggingContext()) {
                Log.Write("Some stuff inside the context.");
                throw new Exception();
            }
        } catch {
            Log.Write("Man, that was a heavy exception caught from inside a child logging context!");
        } finally {
            Log.Write("Some final stuff.");
        }
    }
}


답변

Dispose 패턴의 목적은 관리되는 리소스와 관리되지 않는 리소스를 모두 정리하는 메커니즘을 제공하는 것이며, 발생하는시기는 Dispose 메서드의 호출 방식에 따라 다릅니다. 예를 들어, 목록을 지우면 폐기되는 컬렉션에 영향을 미치지 않으므로 Dispose를 사용하면 실제로 Dispose와 관련된 작업을 수행하지 않습니다. 마찬가지로 변수를 null로 설정하는 호출도 GC에 영향을 미치지 않습니다.

Dispose 패턴을 구현하는 방법에 대한 자세한 내용 은이 기사 를 참조하십시오. 그러나 기본적으로 다음과 같습니다.

public class SimpleCleanup : IDisposable
{
    // some fields that require cleanup
    private SafeHandle handle;
    private bool disposed = false; // to detect redundant calls

    public SimpleCleanup()
    {
        this.handle = /*...*/;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
                if (handle != null)
                {
                    handle.Dispose();
                }
            }

            // Dispose unmanaged managed resources.

            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

여기서 가장 중요한 방법은 Dispose (bool)이며 실제로 두 가지 상황에서 실행됩니다.

  • disposing == true : 메소드가 사용자 코드에 의해 직접 또는 간접적으로 호출되었습니다. 관리 및 관리되지 않는 리소스를 폐기 할 수 있습니다.
  • disposing == false : 종료자가 내부에서 런타임에 의해 메소드를 호출했으며 다른 오브젝트를 참조하지 않아야합니다. 관리되지 않는 리소스 만 폐기 할 수 있습니다.

GC가 정리를 처리하게하는 문제는 GC가 수집주기를 실행할시기를 실제로 제어 할 수 없다는 것입니다 (GC.Collect ()를 호출 할 수는 있지만 실제로는 그렇게하지 않아야합니다). 필요 이상으로 길다. Dispose ()를 호출한다고해서 실제로 수집주기가 발생하거나 GC가 개체를 수집 / 해제하지는 않습니다. 사용 된 리소스를보다 결정적으로 정리하고 GC에이 정리가 이미 수행되었음을 알리는 수단을 제공합니다.

IDisposable 및 dispose 패턴의 요점은 즉시 메모리를 해제하지 않습니다. Dispose를 호출하면 실제로 메모리를 즉시 해제 할 수있는 유일한 시간은 == false 시나리오를 처리하고 관리되지 않는 리소스를 조작 할 때뿐입니다. 관리 코드의 경우 GC가 수집주기를 실행할 때까지 실제로 메모리를 회수하지 않습니다. 수집주기는 실제로 제어 할 수 없습니다 (이미 언급 한 GC.Collect () 호출은 좋지 않습니다).

.NET의 문자열은 정렬되지 않은 리소스를 사용하지 않고 IDisposable을 구현하지 않으므로 시나리오를 실제로 유효하지 않습니다. 강제로 “정리”할 수있는 방법이 없습니다.


답변

Dispose가 호출 된 후에는 개체의 메서드에 대한 추가 호출이 없어야합니다 (물론 Dispose에 대한 추가 호출을 허용해야하지만). 따라서 문제의 예는 바보입니다. Dispose가 호출되면 객체 자체를 버릴 수 있습니다. 따라서 사용자는 해당 전체 객체에 대한 모든 참조를 버리고 (null로 설정) 내부의 모든 관련 객체가 자동으로 정리됩니다.

관리 / 관리되지 않는 일반적인 질문과 다른 답변의 토론에 관해서는이 질문에 대한 답은 관리되지 않는 리소스의 정의로 시작해야한다고 생각합니다.

요약하자면 시스템을 상태로 만들기 위해 호출 할 수있는 함수가 있고 해당 상태에서 시스템을 다시 가져 오기 위해 호출 할 수있는 다른 기능이 있다는 것입니다. 이제 일반적인 예에서 첫 번째 것은 파일 핸들을 반환하는 함수이고 두 번째는에 대한 호출 일 수 있습니다 CloseHandle.

그러나 이것이 핵심입니다. 일치하는 함수 쌍이 될 수 있습니다. 하나는 상태를 만들고 다른 하나는 상태를 찢습니다. 상태가 구축되었지만 아직 해제되지 않은 경우 리소스 인스턴스가 존재합니다. 적절한 시간에 분류가 발생하도록 준비해야합니다. 리소스는 CLR에서 관리하지 않습니다. 자동으로 관리되는 유일한 자원 유형은 메모리입니다. GC와 스택의 두 가지 종류가 있습니다. 값 유형은 스택에 의해 관리되거나 참조 유형 내에서 승차감을 치거나 GC가 참조 유형을 관리합니다.

이러한 함수는 자유롭게 인터리브 될 수있는 상태 변경을 야기하거나 완벽하게 중첩되어야 할 수도 있습니다. 상태 변경은 스레드로부터 안전하거나 그렇지 않을 수 있습니다.

법무부의 질문에 나오는 예를보십시오. 로그 파일 들여 쓰기에 대한 변경 사항은 완벽하게 중첩되어야합니다. 그렇지 않으면 모두 잘못됩니다. 또한 스레드 안전하지 않을 것입니다.

가비지 수집기를 사용하여 관리되지 않는 리소스를 정리할 수 있습니다. 그러나 상태 변경 기능이 스레드 안전하고 두 상태가 수명이 겹치는 경우에만 가능합니다. 따라서 법무부의 자원에 대한 예에는 종결자가 없어야합니다! 그것은 아무도 도움이되지 않습니다.

이러한 종류의 리소스의 경우 종료 자없이을 구현할 수 있습니다 IDisposable. 파이널 라이저는 절대적으로 선택 사항입니다. 이것은 많은 책에서 언급되거나 언급되지 않은 것입니다.

그런 다음 using명령문 을 사용하여 Dispose호출 될 가능성을 확인해야 합니다. 이것은 본질적으로 스택으로 라이딩을 맞추는 것과 같습니다 (파이널 라이저는 GC using에 있고 스택에 있습니다).

누락 된 부분은 Dispose를 수동으로 작성하여 필드와 기본 클래스를 호출해야한다는 것입니다. C ++ / CLI 프로그래머는 그렇게 할 필요가 없습니다. 컴파일러는 대부분의 경우이를 위해이를 작성합니다.

완벽하게 중첩되고 스레드로부터 안전하지 않은 상태에 대해 선호하는 대안이 있습니다 (IDisposable을 피하면 IDisposable을 구현하는 모든 클래스에 종료자를 추가하는 것을 거부 할 수없는 사람과의 논쟁이 필요하지 않습니다) .

클래스를 작성하는 대신 함수를 작성합니다. 이 함수는 델리게이트가 다음을 호출하도록 허용합니다.

public static void Indented(this Log log, Action action)
{
    log.Indent();
    try
    {
        action();
    }
    finally
    {
        log.Outdent();
    }
}

그리고 간단한 예는 다음과 같습니다.

Log.Write("Message at the top");
Log.Indented(() =>
{
    Log.Write("And this is indented");

    Log.Indented(() =>
    {
        Log.Write("This is even more indented");
    });
});
Log.Write("Back at the outermost level again");

전달되는 람다는 코드 블록의 역할을하므로 using더 이상 발신자가 악용 할 위험이 없다는 점을 제외하고는와 동일한 목적을 위해 자체 제어 구조를 만드는 것과 같습니다 . 리소스 정리에 실패 할 수있는 방법은 없습니다.

자원이 수명이 겹칠 수있는 종류 인 경우이 기술은 유용하지 않습니다. 자원 A, 자원 B, 자원 A를 종료 한 다음 나중에 자원 B를 종료 할 수 있기를 원하기 때문입니다. 사용자가 이처럼 완벽하게 중첩되도록 강요 한 경우 그러나 그런 다음 IDisposable스레드 안전을 구현하지 않은 한 아직 종료자가 없어도 사용해야합니다 (무료는 아닙니다).


답변

IDisposable을 사용하는 시나리오 : 관리되지 않는 리소스 정리, 이벤트 구독 취소, 연결 끊기

IDisposable 구현에 사용하는 관용구 ( threadsafe 아님) :

class MyClass : IDisposable {
    // ...

    #region IDisposable Members and Helpers
    private bool disposed = false;

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing) {
        if (!this.disposed) {
            if (disposing) {
                // cleanup code goes here
            }
            disposed = true;
        }
    }

    ~MyClass() {
        Dispose(false);
    }
    #endregion
}


답변

그러나이 코드는 완전히 중복되고 불필요하며 가비지 수집기가 다른 방법으로 수행하지 않는 작업을 수행하지 않습니다 (MyCollection의 인스턴스가 범위를 벗어난 경우) .Clear().

편집에 대한 답변 : 정렬 내가 이렇게하면 :

public void WasteMemory()
{
    var instance = new MyCollection(); // this one has no Dispose() method
    instance.FillItWithAMillionStrings();
}

// 1 million strings are in memory, but marked for reclamation by the GC

메모리 관리를 위해 기능적으로 동일합니다.

public void WasteMemory()
{
    var instance = new MyCollection(); // this one has your Dispose()
    instance.FillItWithAMillionStrings();
    instance.Dispose();
}

// 1 million strings are in memory, but marked for reclamation by the GC

이 순간에 메모리를 정말로 확보해야하는 경우,을 호출하십시오 GC.Collect(). 그러나 여기서 할 이유가 없습니다. 필요할 때 메모리가 해제됩니다.


답변

MyCollection어쨌든 가비지 수집 될 예정 이라면 폐기 할 필요가 없습니다. 그렇게하면 CPU가 필요 이상으로 떨 어지고 가비지 수집기가 이미 수행 한 미리 계산 된 일부 분석이 무효화 될 수도 있습니다.

IDisposable관리되지 않는 리소스와 함께 스레드가 올바르게 배치되었는지 확인 하는 데 사용 합니다.

편집 Scott의 의견에 대한 답변 :

GC 성능 측정 항목이 영향을받는 유일한 시간은 [sic] GC.Collect ()를 호출 할 때입니다. “

개념적으로 GC는 객체 참조 그래프의보기를 유지하고 스레드의 스택 프레임에서 이에 대한 모든 참조를 유지합니다. 이 힙은 상당히 클 수 있으며 많은 메모리 페이지에 걸쳐 있습니다. 최적화로서 GC는 불필요하게 페이지를 다시 스캔하지 않도록 자주 변경되지 않는 페이지 분석을 캐시합니다. GC는 페이지의 데이터가 변경 될 때 커널로부터 알림을 수신하므로 페이지가 더럽고 재검색이 필요하다는 것을 알고 있습니다. 컬렉션이 Gen0에 있으면 페이지의 다른 것들도 변경 될 가능성이 있지만 Gen1 및 Gen2에서는 그 가능성이 적습니다. 이 플랫폼에서 Silverlight 플러그인을 사용하기 위해 GC를 Mac으로 이식 한 팀의 경우 Mac OS X에서는 이러한 후크를 사용할 수 없었습니다.

불필요한 자원 폐기에 대한 또 다른 요점 : 프로세스가 언로드되는 상황을 상상해보십시오. 프로세스가 얼마 동안 실행되었다고 상상해보십시오. 해당 프로세스의 많은 메모리 페이지가 디스크로 스왑되었을 수 있습니다. 최소한 L1 또는 L2 캐시에는 없습니다. 이러한 상황에서는 프로세스가 종료 될 때 운영 체제에서 해제 될 ‘릴리스’리소스로 모든 데이터 및 코드 페이지를 메모리로 다시 스왑하기 위해 언로드하는 응용 프로그램이 필요하지 않습니다. 이는 관리 대상 및 특정 관리되지 않는 리소스에도 적용됩니다. 백그라운드가 아닌 스레드를 활성 상태로 유지하는 리소스 만 폐기해야합니다. 그렇지 않으면 프로세스가 활성 상태로 유지됩니다.

이제 정상적인 실행 중에 관리되지 않는 메모리 누수를 피하기 위해 @fezmonkey가 데이터베이스 연결, 소켓, 창 핸들을 가리 키기 때문에 올바르게 정리해야하는 임시 리소스가 있습니다 . 이들은 폐기해야 할 종류입니다. 스레드를 소유하는 클래스를 작성하면 (그리고 소유주가 스레드를 작성 했으므로 적어도 코딩 스타일에 따라 중지되도록 할 책임이 있음을 의미 함) 해당 클래스는 아마도 IDisposable스레드를 구현 하고 해제 해야합니다 Dispose.

.NET 프레임 워크는 IDisposable이 클래스 폐기 해야 한다는 신호를 개발자에게 경고하기 위해 인터페이스로 사용합니다 . IDisposable처리가 선택적 인 프레임 워크의 유형 (명시 적 인터페이스 구현 제외)을 생각할 수 없습니다 .


카테고리C#

답글 남기기