2010-12-08 5 views
7

다음과 같이 주어집니다 :GC 콜을 교착 상태로 만들 수 있습니까? 콜렉트와 GC.

GC.Collect(GC.MaxGeneration); 
GC.WaitForPendingFinalizers(); 
GC.Collect(GC.MaxGeneration); 

다중 스레드 및 가비지 수집 모드를 고려하면 WaitForPendingFinalizers에서 어떤 상황에서 교착 상태가 발생합니까?

참고 : GC.Collect을 호출하면 안되는 이유에 대한 대답은 찾고 있지 않습니다.

+2

이것은 엄격하게 선제적인 질문입니까, 아니면 실제 교착 상태가 발생합니까? (문제를 해결할 경우 최종 메서드에 대한 코드를 게시하는 것이 유용 할 것입니다.) –

답변

6
// causes a deadlock when built with release config and no debugger attached 
// building in debug mode and/or attaching the debugger might keep 
// badIdea alive for longer, in which case you won't see the deadlock 
// unless you explicitly set badIdea to null after calling Monitor.Enter 

var badIdea = new BadIdea(); 
Monitor.Enter(badIdea); 

GC.Collect(GC.MaxGeneration); 
GC.WaitForPendingFinalizers(); 
GC.Collect(GC.MaxGeneration); 

// ... 

public class BadIdea 
{ 
    ~BadIdea() 
    { 
     lock (this) 
     { 
      // ... 
     } 
    } 
} 
1

제프리 리히터 (Jeffrey Richter)가 설명한 WaitForPendingFinalizers에서 유명한 교착 상태가 있습니다. 여기에 표시됩니다 : http://haacked.com/archive/2005/04/12/neverlockthis.aspx

 
class MyClass 
{ 

private bool isDisposed = false; 

    ~MyClass() 
    { 
     lock(this) 
     { 
      if(!isDisposed) 
      { 
       // ... 
      } 
     } 
    } 
} 
... 
MyClass instance = new MyClass(); 

Monitor.Enter(instance); 
instance = null; 

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

가 그것은 잘못된 (이) 잠금의 사용에 의해 발생합니다. 어쨌든 WaitForPendingFinalizers가 잠긴 경우입니다.하지 않는 한 당신이 당신의 Finalize 방법 내에서 관리되는 개체에 액세스하는 GC.CollectGC.WaitForPendingFinalizers를 호출 할 때

1

당신은 교착 상태의 어떤 종류가 발생하지 않습니다. public 범위가있는 다른 객체의 메서드를 호출하면 이 교착 상태를 포함하여 예기치 않은 결과를 초래할 수 있습니다. 그 이유는 당신이 다른 객체의 잠금 패턴을 완전히 통제하지 못하기 때문입니다. 파이널 라이저 메소드가 액세스하려고 시도하는 동안 누군가에 의해 잠길 수 있습니다.

또한, 종료 자에 명시 적으로 this 잠금 거의 LukeH의 대답은 보여으로, 교착 상태의 원인을 보장합니다. Jeffrey Richter의 원래 기사 인 here을 읽을 수 있습니다.

일반적으로 최종 사용자에게는 관리되지 않는 리소스 만 릴리스해야하므로 교착 상태에 대한 우려가 완화됩니다.

+0

실제로 최종 마무리 가능한 개체가 다른 관리되는 개체에 대한 참조를 보유하는 것이 유용한 일부 상황이 있습니다. 예를 들어'Bitmap' 객체는 비싸기 때문에 16x16 아이콘 수백 개를 저장해야하는 프로그램은 각각 64 개의 아이콘을 저장할 수있는 16x1024 픽셀 비트 맵을 할당하는 클래스를 정의한 다음 각각이 참조를 보유하는 객체를 반환합니다 비트 맵 할당 자 (bitmap-allocator)에 어떤 부분이 '소유하고 있는지'와 함께 표시됩니다. 이러한 '비트 맵 조각'객체가 처리되면 할당자는 큰 비트 맵의 ​​해당 부분을 다른 사람이 사용할 수있게합니다. – supercat

+0

더 큰 비트 맵에 대한 강력한 참조가 '비트 맵 조각'객체 내에있는 경우에도 그러한 객체를 모두 버리면 더 큰 비트 맵이 마무리 될 수 있고 비트 맵과 관련된 '비트 맵 조각'객체 중 하나만 남겨 두는 것이 모두 취소됩니다 모든 것을 할당 된 채로 남겨 두지 만 대부분 다른 목적으로는 사용할 수 없습니다. 파이널 라이저를 비트 맵 조각 객체에 추가하면 마스터 객체가 버려진 조각을 재사용 할 수 있습니다. 물론 이러한 코드는 교착 상태 나 다른 쓰레딩을 피하기 위해주의 깊게 작성해야하지만 여전히 유용 할 수 있습니다. – supercat

+0

이 답변이나 질문과 관련이 있는지 이해할 수 없습니다. @supercat –