2010-04-19 2 views
6

.Net에서 가비지 수집과 관련하여 몇 가지 흥미로운 동작이 나타났습니다..Net에서 가비지 수집을 트리거하는 기준

다음 프로그램은 매우 빨리 OutOfMemoryException을 throw합니다 (32 비트 2GB 시스템에서는 1 초 미만). Foo finalizer는 호출되지 않습니다. rand.nextBytes 라인이 주석 인 경우

class Foo 
{ 
    Guid guid = Guid.NewGuid(); 
    byte[] buffer = new byte[1000000]; 

    static Random rand = new Random(); 
    public Foo() 
    { 
     // Uncomment the following line and the program will run forever. 
     // rand.NextBytes(buffer); 
    } 

    ~Foo() 
    { 
     // This finalizer is never called unless the rand.NextBytes 
     // line in the constructor is uncommented. 
    } 

    static public void Main(string args[]) 
    { 
     for (; ;) 
     { 
      new Foo(); 
     } 
    } 
} 

, 그것은 광고 인해서 실행하고 푸 파이널 정기적으로 호출됩니다. 왜 그런가요?

가장 좋은 추측은 전자의 경우 CLR 또는 Windows VMM 중 하나가 실제 메모리를 할당하는 것을 게으른 것입니다. 버퍼는 결코 기록되지 않으므로 실제 메모리는 사용되지 않습니다. 주소 공간이 부족하면 시스템이 충돌합니다. 후자의 경우 시스템의 주소 공간이 부족해지기 전에 실제 메모리가 부족하여 GC가 실행되고 개체가 수집됩니다.

그러나 여기서는 내가 알지 못하는 부분이 있습니다. 내 이론이 맞다고 가정하면 주소 공간이 부족할 때 GC가 트리거하지 않는 이유는 무엇입니까? 내 이론이 틀렸다면, 진짜 설명은 뭐니?

답변

1

이 코드는 내 컴퓨터에서 안정적인 18MB로 실행됩니다.이 코드는 (XP SP3 x86, .Net 3.5 SP1, 듀얼 코어)입니다.

컴퓨터에서 일어나는 일은 행이 주석 처리 될 때 프로그램이 가비지 컬렉터 스레드가 할당을 해제하기 전에 할당하는 데 많은 시간을 소비하고 너무 많은 메모리를 할당하는 것입니다. 이 줄의 주석 처리를 제거하면 프로그램이 할당하는 데 훨씬 적은 시간을 소비하므로 GC 스레드가 실행되기 전에 너무 많은 할당을 할 수 없습니다.

주석 처리 된 행을 Thread.Sleep(0)으로 바꾸어보십시오. 충돌이 없다면 아마 맞을 것입니다.


그냥 보조 노트로, 혹시 파이널에 의존해서는 안 - 객체도 전혀 GC'ed, 또는 즉시 때 호출 할 보장 할 수 없습니다. 대신, 실제 코드에서 IDisposable 인터페이스를 구현하고 (예. 등 공유 네트워크/파일 리소스를 해제)

+0

I는 프로그래머가 그것을 잊어 버린 경우에도 Dispose()를 호출 할 매우 중요한 것입니다 경우에만 종료자를 사용 네가 옳은 대답을하고 있는지 확신 할 수 없지만, 너는 나를 흥미로운 길로 가게했다. 나는 실행중인 두 개의 가상 PC (512MB)를 종료하고 나는 당신의 행동을 얻는다. VPC를 다시로드하면 원래의 충돌 동작이 발생합니다. –

+0

'GC' 클래스에서 몇 가지 흥미로운 기능들이 있지만, 실제 코드에서는 결코 사용해서는 안됩니다. –

+0

VPC를 실행하고 Thread.Sleep (0)을 제자리에두면 프로그램이 영원히 실행됩니다. 이제 질문이 바뀝니다 ... GC가 할당 실패로 인해 자동으로 트리거되지 않는 이유는 무엇입니까? –

관련 문제