릴리스 대상의 .NET 코드를 컴파일 할 때 가비지 수집기가 실제로 공격적 일 수 있습니다. 즉, 잠재적 가능성이 있습니다.
예 보자이 예에서
public void Test()
{
FileStream stream = new FileStream(....);
stream.Write(...);
SomeOtherMethod();
}
를 Stream.Write
에 대한 호출이 리턴되면,이 방법은 stream
변수에 대한 더 이상의 사용이 없으며, 따라서, 즉, 범위를 벗어난 것으로 간주되고 FileStream
개체가 컬렉션에 적합합니다. SomeOtherMethod
에 대한 호출 중에 가비지 콜렉터가 실행되면 스트림 오브젝트가 수집 될 수 있습니다.
은 편집 : @Greg Beech이 코멘트에서 지적 하듯이, 객체는 인스턴스 메서드가 현재 그것을 실행하는 경우에도 수집 할 수 있습니다.
예를 들어, FileStream.Write
의 코드는 다음과 같습니다 가정 해 봅시다 :
는
public void Write(byte[] buffer, ...)
{
IntPtr unmanagedHandle = _InternalHandleField;
SomeWindowsDll.WriteBuffer(unmanagedHandle, ...);
...
여기 방법은 먼저 관리되지 않는 핸들을 포함하는 내부 필드를 잡고. 이 문제가 발생하기 전에 개체가 수집되지 않습니다. 하지만 이것이 P/Invoke 호출로 전환하기 전에 Write에서 액세스되는 객체의 마지막 필드 또는 객체의 마지막 인스턴스 메소드 인 경우 이제 객체가 컬렉션에 적합합니다.
FileStream에는 관리되지 않는 파일 핸들이 있기 때문에 (아마도 내가 알지 못합니다) 파이널 라이저가 있으므로 아마도 관리되지 않는 파일 핸들이 WriteBuffer를 호출하기 전에 닫힐 위험이 있습니다 완료되었습니다. 즉, .Write
의 가정 된 구현이 위와 같을 경우 가장 가능성이 높습니다. 당신이 이것을 방지 스트림 객체가 어떤 이유 SomeOtherMethod
에 호출 기간 동안 살 수 있도록하고자하는 경우
, 당신은 어떤 방법으로 개체를 "사용"고 호출 후 코드를 삽입해야합니다.
public void Test()
{
FileStream stream = new FileStream(....);
stream.Write(...);
SomeOtherMethod();
GC.KeepAlive(stream);
}
방법은 아무것도하지 않습니다, 그러나 그것은 표시했습니다 : 당신이 메서드를 호출하거나 개체의 속성을 읽을 수 없다 경우에, 당신은 그것을 할 GC.KeepAlive
의 인공 "사용"방법을 사용할 수 있습니다 속성을 사용하여 최적화되지 않습니다. 이것은 스트림 변수가 현재 SomeOtherMethod
에 대한 호출 기간 동안 사용 중이며 그것에 저장된 FileStream
오브젝트가 그 시간 동안 수집되지 않는다는 것을 의미합니다.
그게 전부입니다. GC.KeepAlive
은 아무 것도 영구적으로 남기지 않고 호출 된 후에도 객체의 수명을 변경하지 않고 가비지 콜렉터가 객체를 수집하지 못하게하는 특정 시점에서 변수를 "사용"하는 코드를 추가하기 만합니다.
나는이 방법에 대해 배웠습니다, 또는 오히려,이 방법의 요점이처럼 보였다 일부 코드를 어려운 방법 : 나는
IDisposable
를 구현하는 객체의 인스턴스를 생성
public void Test()
{
SomeObjectThatCanBeDisposed d = new SomeObjectThatCanBeDisposed();
SomeInternalObjectThatWillBeDisposed i = d.InternalObject();
CallSomeMethod(i);
}
공지 사항 및 원래의 경우 finalizer도 구현했습니다. 그런 다음 추적 할 객체를 "낚아 채"하고 일회용 객체를 설정하는 방식 (잘못)은 일단 finalizer가 실행되면 내부 객체 (불량)도 처리한다는 것입니다. 위의 코드에서 d는 일단 내부 객체가 추출되면 컬렉션에 적합하게되고 객체가 수집되면 추출한 객체를 폐기하여 완성됩니다. 즉, CallSomeMethod
을 호출하는 동안 메서드에 전달 된 객체가 없어졌으며 그 이유를 이해할 수 없었습니다.
물론 위 코드의 픽스는 GC.KeepAlive
을 사용하는 것이 아니라 잘못된 finalizer를 수정하는 것이었지만 "내부 개체"가 관리되지 않는 리소스 인 경우 상황이 다를 수있었습니다.
이제는 키보드 훅에 대해서도 정적 필드와 같은 루트에 참조를 저장하는 경우 살아있는 것으로 유지되는 객체의 멤버 필드 등을 파란색으로 수집해서는 안됩니다 .
좋습니다. 빠른 답변 감사합니다. – Alex
훌륭한 답변, 감사합니다. Lasse. – Segfault
좋은 설명이지만 하나의 작은 수정 ... 인스턴스 메서드가 개체에서 필요한 상태를 추출한 후에도 개체 메서드가 실행되는 동안에도 개체를 수집 할 수 있습니다. 따라서'FileStream' 객체는'Write'에 대한 호출이 반환되기 전에도 수집 될 수 있습니다. 자세한 내용은 http://blogs.msdn.com/cbrumme/archive/2003/04/19/51365.aspx를 참조하십시오. –