[C#] 언제 GC.Collect에 전화 할 수 있습니까?

일반적인 조언은 GC.Collect코드에서 호출해서는 안되지만 이 규칙의 예외는 무엇입니까?

가비지 수집을 강제하는 것이 합리적 일 수있는 매우 구체적인 몇 가지 사례 만 생각할 수 있습니다.

마음에 떠오르는 한 가지 예는 서비스로, 간격을두고 일어나서 몇 가지 작업을 수행 한 다음 오랫동안 잠 들어 있습니다. 이 경우, 유휴 상태가 될 프로세스가 필요한 것보다 많은 메모리를 보유하지 못하도록 수집을 강제하는 것이 좋습니다.

전화 할 수있는 다른 경우가 GC.Collect있습니까?



답변

중요한 개체 집합, 특히 1 세대와 2 세대에있는 것으로 의심되는 개체 집합이 이제 가비지 수집 대상이되고 작은 성능 저하 측면에서 수집하기에 적절한시기가되었다고 믿을만한 충분한 이유가있는 경우 .

좋은 예는 방금 큰 양식을 닫은 경우입니다. 이제 모든 UI 컨트롤을 가비지 수집 할 수 있으며 양식을 닫을 때 아주 짧은 일시 중지는 사용자에게 눈에 띄지 않을 것입니다.

업데이트 2.7.2018

.NET 4.5으로 -이 GCLatencyMode.LowLatencyGCLatencyMode.SustainedLowLatency. 이 모드 중 하나를 시작하거나 종료 할 때는을 사용하여 전체 GC를 강제 실행하는 것이 좋습니다 GC.Collect(2, GCCollectionMode.Forced).

.NET 4.6부터는 GC.TryStartNoGCRegion(읽기 전용 값을 설정하는 데 사용되는 GCLatencyMode.NoGCRegion) 방법이 있습니다. 이것은 충분한 메모리를 확보하기 위해 전체 차단 가비지 수집을 수행 할 수 있지만 일정 기간 동안 GC를 허용하지 않는다면 전후에 전체 GC를 수행하는 것이 좋습니다.

출처 : Microsoft 엔지니어 Ben Watson : 고성능 .NET 코드 작성 , 2 차 Ed. 2018.

보다:


답변

나는 GC.Collect조잡한 성능 / 프로파일 러 테스트 리그를 작성할 때만 사용 합니다. 즉, 테스트 할 코드 블록이 두 개 이상 있습니다.

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestA(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestB(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
...

그래서 TestA()TestB()가능한 한 유사한 상태로 실행 – 즉 TestB()때문에 단지 망치되지 않습니다 TestA매우 가까운 티핑 포인트를 떠났다.

전형적인 예는 간단한 콘솔 exe ( Main예를 들어 여기에 게시 할 수 있는 방법)인데, 이는 문자열 연결과와의 차이점을 보여줍니다 StringBuilder.

내가 정확한 것을 필요로한다면, 이것은 완전히 독립적 인 두 가지 테스트 일 것입니다.하지만 종종 테스트 중에 GC를 최소화 (또는 정규화)하여 동작에 대한 거친 느낌을 얻으려는 경우에 충분합니다.

생산 코드 중에? 나는 아직 그것을 사용하지 않았다 ;-p


답변

모범 사례는 대부분의 경우 가비지 콜렉션을 강제 실행하지 않는 것입니다. (내가 작업 한 모든 시스템은 가비지 콜렉션을 강제 실행하고, 해결하면 가비지 콜렉션을 강제 실행해야 할 필요성을 제거하고 시스템 속도를 크게 높일 수있는 문제를 강조했습니다.)

있습니다 몇 가지 경우 다음 가비지 컬렉터가하는 메모리 사용에 대해 더 알고있다. 다중 사용자 응용 프로그램이나 한 번에 하나 이상의 요청에 응답하는 서비스에서는 그렇지 않을 수 있습니다.

그러나 일부 배치 유형 처리 에서는 GC보다 더 많은 것을 알고 있습니다. 예를 들어 응용 프로그램을 고려하십시오.

  • 명령 행에 파일 이름 목록이 제공됩니다.
  • 단일 파일을 처리 한 후 결과 파일에 결과를 기록합니다.
  • 파일을 처리하는 동안 파일 처리가 완료 될 때까지 수집 할 수없는 많은 상호 연결된 개체를 만듭니다 (예 : 구문 분석 트리).
  • 처리 한 파일간에 일치 상태를 유지하지 않습니다 .

당신은 할 수 있습니다 각 파일을 처리 한 후에는 전체 가비지 컬렉션을 강제해야 테스트 (주의 후) 케이스를 만들 수.

또 다른 경우는 일부 항목을 처리하기 위해 몇 분마다 깨우는 서비스이며 잠자는 동안 상태를 유지하지 않는 서비스입니다 . 그럼 그냥 잠에 가기 전에 전체 수집을 강제 할 수 있습니다 보람.

컬렉션을 강제로 고려할 수있는 유일한 시간은 최근에 많은 객체가 생성되었고 현재 참조되는 객체가 거의 없다는 것을 알 때입니다.

나는 GC를 스스로 강요하지 않고이 유형의 것에 대한 힌트를 줄 수있을 때 가비지 수집 API를 사용하려고합니다.

Rico Mariani의 성능 팁 “참조


답변

한 가지 경우는 WeakReference 를 사용하는 코드를 단위 테스트하려고 할 때 입니다.


답변

메시지, RPC 요청에 반응하거나 데이터베이스 또는 프로세스를 지속적으로 폴링하는 24/7 또는 24/6 시스템의 경우 메모리 누수를 식별하는 방법이 유용합니다. 이를 위해 처리를 일시적으로 일시 중단 한 다음 전체 가비지 수집을 수행하는 메커니즘을 응용 프로그램에 추가하는 경향이 있습니다. 이렇게하면 시스템이 남아있는 메모리가 합법적으로 오래 사용 된 메모리 (캐시, 구성 등)이거나 ‘누설 된'(루트가 예상되지 않았지만 실제로는 근본 인 객체) 상태 인 대기 상태가됩니다.

이 메커니즘을 사용하면 활성 처리의 노이즈로 보고서가 흐리게 표시되지 않으므로 메모리 사용량을 훨씬 쉽게 프로파일 링 할 수 있습니다.

모든 가비지를 확보하려면 두 가지 콜렉션을 수행해야합니다.

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

첫 번째 컬렉션은 종료자를 가진 모든 객체를 마무리하지만 실제로는 이러한 객체를 가비지 수집하지 않습니다. 두 번째 GC는 이러한 최종 객체를 가비지 수집합니다.


답변

가비지 수집기에서 제공하지 않는 앱의 특성에 대해 알고있는 경우 GC.Collect ()를 호출 할 수 있습니다. 저자로서 이것이 가능성이 높다고 생각하고 싶어합니다. 그러나 진실은 GC가 꽤 잘 작성되고 테스트 된 전문가 시스템에 해당하며, 저수준 코드 경로에 대해 알지 못하는 경우는 거의 없습니다.

추가 정보가있는 위치를 생각할 수있는 가장 좋은 예는 유휴 기간과 매우 바쁜 기간 사이를 순환하는 앱입니다. 사용량이 많은 기간 동안 가능한 최고의 성능을 원하므로 유휴 시간을 사용하여 정리를 수행하려고합니다.

그러나 대부분의 경우 GC는 어쨌든 이것을 할만 큼 똑똑합니다.


답변

메모리 조각화 솔루션으로. 많은 데이터를 메모리 스트림에 쓰는 동안 (네트워크 스트림에서 읽음) 메모리 예외가 발생했습니다. 데이터는 8K 청크로 작성되었습니다. 128M에 도달 한 후 사용 가능한 메모리가 많지만 예외가 발생했습니다 (그러나 조각화 됨). GC.Collect ()를 호출하면 문제가 해결되었습니다. 수정 후 1G 이상을 처리 할 수있었습니다.