폐기의 포인트 입니다 관리되지 않는 리소스를 해제 할 수 있습니다. 특정 시점에 수행해야합니다. 그렇지 않으면 정리되지 않습니다. 가비지 컬렉터가 모르는 방법 전화 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()
합니까? 그러면 관리되지 않는 리소스 가 누출 될 것입니다 !
참고 : 결국 가비지 수집기가 백그라운드 스레드에서 실행되고 사용되지 않는 개체와 관련된 메모리를 해제하기 때문에 관리되는 리소스가 누출되지 않습니다 . 여기에는 개체 및 사용하는 모든 관리되는 개체 (예 : Bitmap
및 DbConnection
)가 포함됩니다.
사람이 전화를 잊어 버린 경우 에도 베이컨을 저장할 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 가 아는 모든 것이 잘못되었을 때
따라서 올바른 종료자를 작성하는 것은 실제로 매우 어렵습니다. 제가 드릴 수있는 최선의 조언은 시도하지 않는 것 입니다.