폐기와 가비지 수집을 분리하는 것이 중요합니다. 그것들은 완전히 별개의 것들이며, 한 가지 공통점이 있습니다.
Dispose
, 가비지 수집 및 마무리
using
문 을 작성할 때 try / finally 블록에 대한 구문 설탕 일 뿐이므로 문 Dispose
본문의 코드 using
가 예외를 throw 하더라도 호출됩니다 . 이 없는 오브젝트가 블록의 끝에서 가비지 수집이 있음을 의미한다.
폐기는 관리되지 않는 리소스 (비 메모리 리소스)에 대한 것입니다. UI 핸들, 네트워크 연결, 파일 핸들 등이 될 수 있습니다. 이들은 제한된 리소스이므로 일반적으로 가능한 한 빨리 해제해야합니다. IDisposable
유형이 관리되지 않는 리소스를 직접 (일반적으로를 통해 IntPtr
) 또는 간접적으로 (예 : Stream
, a SqlConnection
등을 통해) "소유"할 때마다 구현해야합니다 .
가비지 수집 자체는 메모리에 관한 것입니다. 가비지 수집기는 더 이상 참조 할 수없는 개체를 찾아 해제 할 수 있습니다. 그래도 항상 가비지를 찾지는 않습니다. 필요한 것을 감지 할 때만 (예 : 힙의 한 "세대"가 메모리가 부족한 경우).
비틀기는 마무리 입니다. 가비지 수집기는 더 이상 도달 할 수 없지만 종료자가있는 개체 목록을 유지합니다 ( ~Foo()
C # 에서처럼 다소 혼란스럽게 작성 됨 -C ++ 소멸자와 같지 않음). 메모리가 해제되기 전에 추가 정리를 수행해야하는 경우를 대비하여 이러한 개체에서 종료자를 실행합니다.
종료자는 해당 유형의 사용자가 규칙적으로 처리하는 것을 잊은 경우 리소스를 정리하는 데 거의 항상 사용됩니다. 그래서 당신은을 열면 FileStream
하지만 전화하는 것을 잊지 Dispose
또는 Close
종료 자는 것, 결국 당신을위한 기본 파일 핸들을 해제. 잘 작성된 프로그램에서 파이널 라이저는 제 생각에는 거의 실행되지 않아야합니다.
변수 설정 null
변수 설정에 대한 한 가지 작은 포인트 null
는 가비지 수집을 위해 거의 필요하지 않습니다. 내 경험상 객체의 "일부"가 더 이상 필요하지 않은 경우는 드물지만 멤버 변수 인 경우 가끔 수행 할 수 있습니다. 지역 변수 인 경우 JIT는 일반적으로 참조를 다시 사용하지 않을 때를 알 수있을만큼 충분히 똑똑합니다 (릴리스 모드에서). 예를 들면 :
StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();
// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);
// These aren't helping at all!
x = null;
sb = null;
// Assume that x and sb aren't used here
이 한 시간 수 에 지역 변수를 설정하는 가치는 null
당신이 루프에있어, 루프의 필요성을 일부 가지 변수를 사용하는 경우입니다 그러나 당신은 당신이 안되는 지점에 도달했습니다 알고있다. 예를 들면 :
SomeObject foo = new SomeObject();
for (int i=0; i < 100000; i++)
{
if (i == 5)
{
foo.DoSomething();
// We're not going to need it again, but the JIT
// wouldn't spot that
foo = null;
}
else
{
// Some other code
}
}
IDisposable / finalizer 구현
그렇다면 자신의 유형이 종료자를 구현해야합니까? 거의 확실하지 않습니다. 관리되지 않는 리소스 만 간접적으로 보유하는 경우 (예 : FileStream
멤버 변수가있는 경우) 자체 종료자를 추가하는 것은 도움이되지 않습니다. 객체가있을 때 스트림은 거의 확실하게 가비지 수집에 적합하므로 신뢰할 수 있습니다. FileStream
종료 자 (필요한 경우-다른 것을 참조 할 수 있음)가 있습니다. 관리되지 않는 리소스를 "거의"직접 보유하고 싶다면 SafeHandle
친구가 되세요. 진행하는 데 약간의 시간이 걸리지 만 종료 자를 다시 작성할 필요가 거의 없음을 의미 합니다 . 일반적으로 리소스 (an IntPtr
) 에 대한 직접적인 핸들이 있고 다음으로 이동해야하는 경우에만 종료자가 필요 합니다.SafeHandle
가능한 한 빨리. (두 개의 링크가 있습니다. 이상적으로는 둘 다 읽으십시오.)
Joe Duffy는 읽을 가치가있는 종료 자 와 IDisposable (많은 똑똑한 사람들과 공동으로 작성)에 대한 매우 긴 지침을 가지고 있습니다. 클래스를 봉인하면 삶이 훨씬 쉬워진다는 사실을 알아 두는 것이 좋습니다 Dispose
. 새로운 가상 Dispose(bool)
메서드 를 호출하도록 재정의하는 패턴 등은 클래스가 상속을 위해 설계된 경우에만 관련이 있습니다.
이것은 약간 엉망 이었지만, 원하는 부분에 대한 설명을 요청하십시오. :)