2011-03-15 2 views
2

원래 VB6로 작성된 응용 프로그램을 사용하여 기능상의 관점에서 C#으로 변환하는 도구를 사용했습니다. 중소 규모의 COM (C++) 객체를 많이 사용하여 대량의 메시지를 처리합니다.많은 COM 개체를 사용하는 C#에서 과도한 메모리 사용

40M 미만의 메모리를 사용하여 실행 된 이전 VB6 앱에서 실행 된 특정 테스트는 C# 응용 프로그램에서 거의 900M을 필요로한다는 것을 눈치 챘습니다. GC.Collect()를 C# 응용 프로그램의 가장 안쪽에있는 메시지 처리 루프에 넣으면 VB6 응용 프로그램과 같거나 적은 메모리가 사용되지만 실제로는 아주 느립니다. 이것은 내가 단어의 절대적인 의미에서 "누설"이 없다고 믿게한다.

그런 다음 AQTime 메모리 프로파일 러를 통해 C# 응용 프로그램을 실행하고 힙에 과도한 수의 COM/C++ 개체가 있다고보고했습니다. 필자는 이것이 COM 객체 주위의 런타임 호출 가능 래퍼가 매우 작았고 참조 된 COM 객체가 상당히 클 경우에도 C#에서 절대로 콜렉션을 트리거하지 않았기 때문이라고 가설을 세웠습니다. C# 응용 프로그램에서 COM 개체 주위에 명시적인 Marshal.ReleaseComObject() 호출을 추가하여이 문제를 해결할 수 있다고 생각했습니다. COM 객체의 수명이 결정하기 쉬운 많은 장소에서이 작업을 수행했습니다. 나는 메모리 사용량이 아주 약간 감소한 것을 보았다.

나는 왜 이것이 더 성공적이지 않았는지 궁금합니다. Marshal 클래스의 정적 메서드를 살펴보면 COM 참조를 처리 할 때 미묘한 부분이 누락되거나 RCW의 참조 횟수가 0에 도달하면 즉시 파괴된다는 가정이 잘못되었다는 사실을 알게되었습니다. .

제가 간과하거나 오해 할 수있는 다른 방법을 시도해 볼 수있는 다른 방법에 대한 제안을 보내 주시면 감사하겠습니다.

+0

당신이 GC.Collect를하지 않으면 어떻게됩니까? 그것은 추락합니까? –

+0

GC.Collect() 호출을 제거하면 메모리 사용량이 약 900M이됩니다. 그것은 결코 추락 한 적이 없지만, 같은 종류의 메모리 사용은 오래된 VB6 앱이 동일한 COM 객체를 사용하는 동안 40M 미만을 사용했을 때 허용되지 않습니다. – Dan

+0

@ Dan : 물리적 인 것이 아니라 가상의 메모리입니다. 과도한 페이징은 "사용 된"전체 메모리보다 더 나은 방법입니다. –

답변

3

좋은 시놉시스 대신 미안하지만 필자는 오랫동안 살았던 시나리오에서 IE와 mshtml을 다루었 기 때문에이 문제를 직접 경험하지 못했습니다.

기사 상태 다음 RCW와 COM 객체 (또는 객체) :

닷넷 기반 응용 프로그램에서 COM 개체를 사용하여, 관련된 두 개체가있다. 가비지 수집은 COM 개체 (크기가 클 수 있음)가 아닌 RCW (작을 수 있음)의 크기 만 인식합니다. 따라서 .NET 기반 응용 프로그램에서 RCW를 릴리스 할 수 있지만 가비지 수집은 메모리가 부족한 경우에도 RCW를 회수하지 못할 수 있습니다. RCW가 메모리에 남아있는 한 관리하는 COM 개체도 메모리에 남아 있습니다.

COM 개체가 메모리에서 해제되도록하는 두 가지 메커니즘, AppDomain 개체와 ReleaseComObject 메서드가 있습니다. AppDomain을 사용하면 COM 개체를 관리하는 가장 간단한 솔루션을 얻을 수 있지만 성능 비용이 발생하고 보안 위험이 발생할 수 있습니다. ReleaseComObject를 사용하면 이러한 비용을 피할 수 있지만보다 세심한 계획과 코딩이 필요합니다.

+0

감사합니다. AppDomain 옵션을 알지 못했지만 성능이 내부 메시지 처리 루프에서 중요하기 때문에 상황에 이상적이지 않을 수 있습니다. – Dan

+0

@ Dan - 루프가 많은 COM 개체를 만들고 릴리스한다고 생각했습니다. 그렇다면, 그 자체가 그다지 할만한 일이 아닙니다. ReleaseComObject는 구현하고 프로파일 링 할 가치가있는 정말 좋은 옵션이라고 생각합니다. –

관련 문제