2010-04-12 5 views
4

GC.KeepAlive()GC.KeepAlive (KeyboardHookPointer) 스팸 관련 문제가 있습니까?

참고 문헌이 메소드가 호출되는 시점에 현재 루틴의 시작부터 가비지 컬렉션을 위해 부적격하게 지정된 객체.

가비지 수집기가 개체를 수집하지 않도록 단순히 GC.KeepAlive가 참조를 저장하는 것 이외에 다른 작업을 수행하는지에 대해 확실하지 않습니다. 그러나 개체의 GC.KeepAlive()를 호출하면 개체가 영구적으로 수집되지 않습니다. 또는 GC.KeepAlive()를 매번 다시 호출해야합니까 (그렇다면 얼마나 자주)? 키보드 훅을 유지하고 싶습니다.

답변

10

릴리스 대상의 .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를 수정하는 것이었지만 "내부 개체"가 관리되지 않는 리소스 인 경우 상황이 다를 수있었습니다.

이제는 키보드 훅에 대해서도 정적 필드와 같은 루트에 참조를 저장하는 경우 살아있는 것으로 유지되는 객체의 멤버 필드 등을 파란색으로 수집해서는 안됩니다 .

+0

좋습니다. 빠른 답변 감사합니다. – Alex

+0

훌륭한 답변, 감사합니다. Lasse. – Segfault

+0

좋은 설명이지만 하나의 작은 수정 ... 인스턴스 메서드가 개체에서 필요한 상태를 추출한 후에도 개체 메서드가 실행되는 동안에도 개체를 수집 할 수 있습니다. 따라서'FileStream' 객체는'Write'에 대한 호출이 반환되기 전에도 수집 될 수 있습니다. 자세한 내용은 http://blogs.msdn.com/cbrumme/archive/2003/04/19/51365.aspx를 참조하십시오. –

2

GC.KeepAlive (GC.Collect뿐 아니라)는 문제를 해결하지 않으므로 프로덕션 코드에 사용하면 안되며 더 많은 경쟁 조건이 생성됩니다. 문제 진단에만 유용합니다.

네이티브 코드에서 관리되는 개체를 사용하고있어 가비지 수집기가 아직 사용 중인지 확인할 수없는 경우 GCHandle.Alloc을 사용해야합니다.

편집 : 일부 지원 근거 :

GC.Kee pAlive는별로 좋지 않습니다. 네이티브 코드에 의한 사용이 반환되기 전에 끝나도록 보장되는 경우에만 확실히 좋습니다. 키보드 후크에는 해당되지 않습니다.

+0

백업을위한 참고 자료 나 특성을 제공하지 않고 작성하는 것은 매우 강력한 성명서입니다. 정교한 케어? –

+0

원래 질문의 기울임 꼴 부분을 읽는 것만으로는 접근법에 대한 따뜻한 모호성을 제공해서는 안됩니다. 이 경우 모든 OA 기기의 우려가 보장됩니다. GCHandle은 "추후 통지 때까지"수집을 막는 올바른 방법입니다. 하지만 잠시 후에 당신에게 참고 문헌을 찾아 드리겠습니다. –

+0

'GC.KeepAlive' 메서드는 경쟁 조건을 만들지 않지만이를 제거 할 수 있습니다. GC는 임의의 순간에 약한 참조 또는 시스템의 자체 완성 대기열을 보지 않고 객체 자체를 검사하게하는 실행 경로가 없으면 시스템을 정리해야한다고 가정하고 시스템은 객체의 'Finalize '메소드를 사용하면 편리하게 실행할 수 있습니다. GC의 관점에서 볼 때 객체에서'GC.KeepAlive'를 호출 할 수있는 실행 경로는 객체 자체를 검사해야 할 필요가있는 것으로 간주됩니다. – supercat

관련 문제