2012-10-08 1 views
2

저는 ESRI의 자체 .NET.NET Interop 어셈블리를 통해 ESRI의 ArcObjects COM 라이브러리를 사용하는 지리 데이터 처리를 위해 .NET 응용 프로그램을 개발 중입니다.GC가 수동으로 그렇게 할 때까지 ArcObjects COM 객체가 종료되지 않는 이유는 무엇입니까?

프로덕션 환경에서 실행 중일 때 프로세스 당 2GB의 메모리 제한에 도달하기 때문에 일부 작업 중에 프로세스가 중단 될 수 있습니다. (ArcObjects는 32 비트 라이브러리입니다.) 일부 처리 단계에서 많은 수의 임시 ArcObjects 지오메트리 개체를 만들 수 있기 때문입니다. FinalReleaseComObject 및 관련 도우미 메서드를 사용하여 이러한 개체를 수동으로 해제하더라도 메모리가 누수되고 결국 메모리가 부족합니다. 그러나 GC가 WaitForPendingFinalizers을 호출하여 메모리를 해제하도록 강제 할 수 있으며 GC.CollectFinalReleaseComObject과 함께 정기적으로 호출하면 메모리 사용을 제어 할 수 있습니다. 그렇지 않으면 프로세스가 종료 될 때까지 (일반적으로 또는 비정상적으로) 많은 오브젝트가 메모리에 남아 있습니다.

첫 번째 질문 : 왜 ArcObjects COM 객체가 보유한 메모리가 즉시 해제되지 않습니까? 또는, 왜 GC가 충돌 된 프로세스가 충돌 이전에 해제 된 COM 개체를 마무리하고 메모리를 회수하는 대신 충돌을 허용합니까?

Windows 7 32 비트를 사용하여 개발하는 동안 응용 프로그램은 Windows 2008 64 비트에서 실행됩니다. 프로덕션 박스에서 프로세스가 중단 될 수 있지만 개발 상자에서는 중단되지 않습니다. 내가 로컬로 디버그 빌드와 함께 Visual Studio에서 일반적으로 실행하기 때문에 수도 있었지만, 나는 또한 디버거 (디버깅하지 않고 시작) 릴리스 빌드를 사용하여 그것을 시도했지만 그때까지도 근처에 많은 것을 사용하지 않았다고 생각 프로덕션 환경에서의 메모리와 충돌하지 않습니다.

두 번째 질문 : 이유가 무엇입니까?

편집 : 이전 실험에서 명시 적으로 호출했지만 GC.Collect 그 자체로는 충분하지 않습니다. 나는 이 뒤 따르는 GC.Collect을 호출하는 유틸리티 메소드를 가지고 있으며, 모든 알고리즘 반복이 메모리 사용을 중단시킨 후에 그것을 호출한다.

답변

5

관리되는 응용 프로그램에 사용되는 COM 개체는 COM 개체의 인터페이스를 관리되는 클라이언트 (관리되는 구성 요소와 관리되지 않는 구성 요소 사이의 다리)로 복제하는 관리되는 개체 인 런타임 호출 가능 래퍼 (RCW) 뒤에 있습니다. 올바르게 기억한다면 실제 COM 인터페이스 참조는 코드가 아닌 RCW가 보유합니다. COM 객체를 해제하면 실제로 RCW가 릴리즈되지만 GC가 정리되기 전까지는 관리 객체 자체가 사라지지 않습니다. 그런 일이 발생하면 RCW가 삭제되고 COM 개체에 대한 마지막 참조가 사라져서 자체를 파괴 할 수 있습니다. (설명서에 따르면 FinalReleaseComObject은 참조 횟수를 0으로 설정해야하지만 이전에는 비슷한 동작을 보아 문서가 올바른지 여부를 묻습니다.

두 번째 질문에 대해서는 다음과 같은 추측을합니다. 스트레스받는 환경에서 시스템이 과부하 상태 일 때 GC가 작동하지 않을 수도 있습니다. 그때 우리는 GC가 우선 순위가 낮은 스레드에서 실행되었고 GC가 결코 정리할 기회가 없었던 응용 프로그램이 너무 많은 CPU를 사용하고 있다고 판단했습니다. 우리는 주기적으로 GC.Collect()을 주기적으로 호출하는 다른 스레드를 추가해야했습니다. 이렇게하면 GC 스레드가 깨어나 마술을 수행하게됩니다. 비슷한 일이 생길 수도 있습니다. (이것도 # 1에서 문제의 원인이 될 수 있습니다.)

+0

RCW에 대해 알고 있지만 COM 개체가 보유한 메모리가 GC가 명시 적으로 실행 되더라도 해제되지 않습니다. 질문을 업데이트했습니다. – Gnat

+0

@Gnat'GC.Collect()'가 GC를 실제로 실행하지 않기 때문에'GC.WaitForPendingFinalizers()'가 필요한 이유가 있습니다.GC가 수집주기를 수행하도록 요청했지만 GC가 다른 스레드에서 실행 중이며 많은 양의 부하로 인해 일정이 잡히지 않을 수 있습니다. 'GC.WaitForPendingFinalizers()'는 다음 수집 사이클이 끝날 때까지 기다려야합니다. 그러면 CPU가 해제되고 GC가 메모리 정리를 실행하고 완료 할 수 있습니다. – xxbbcc

+0

@Gnat 만약 당신이'GC.WaitForPendingFinalizers()'를 호출 할 필요가 있는지 맞다면 (예기한다면), 응용 프로그램이 CPU에 부하를 걸면 기대할 것입니다. 로드가 많고 메모리가 많은 시나리오에서는 GC 스레드가 부족해질 수 있으며 시스템 (또는 프로세스)의 메모리가 부족할 수 있습니다. 내가 언급 한 그 오래된 프로젝트에서 나는 똑같이해야만했다. – xxbbcc

관련 문제