2009-04-11 7 views
2

내 응용 프로그램 중 일부와 해당 응용 프로그램에서 사용하는 dll에서 참조 계산 된 많은 클래스가 있으며, 모두 IRefCounted 인터페이스를 상속하고 구현합니다.C++ : 참조 카운팅 시스템에서 메모리 누수 디버깅

이러한 메모리 누수의 원인을 찾는 데 도움이되도록 각 응용 프로그램에서 존재하는 모든 이러한 참조 횟수가있는 클래스의 목록을 유지 관리해야합니다.

문제는 이러한 사용법이 클래스 사용에 영향을 미치지 않도록 목록의 인스턴스를 관리하는 것입니다 (예를 들어, 포인터를 항상 주위에 전달하여 대신 목록에 연결하는 방법). 과정).

- 이러한 응용 프로그램 중 일부는 한 번에 실행될 수 있으며 동일한 DLL을 사용할 수있는 좋은 기회입니다. 각 응용 프로그램마다 고유 한 개체 목록이 필요하며 해당 응용 프로그램에 의해로드 된 모든 dll 등은 해당 목록을 사용해야합니다 (그러나 하나의 dll은 여러 응용 프로그램에서로드 될 수 있습니다 ...).
- 목록은 응용 프로그램의 다른 모든 전역 변수와 정적 변수 다음에 삭제되어야하므로 목록에 남아있는 객체는 truley가 올바르게 해제되지 않은 객체입니다.

그런 다음 디버거에서 할당되지 않은 객체를 볼 수 있도록 목록의 소멸자에 중단 점을 추가하기 만하면됩니다.

+0

죄송합니다. 무엇이 문제입니까? –

답변

1

나는 COM을 사용하고 있다고 생각합니다.weak pointer을 갖는 방법을 찾아야 인스턴스화 된 객체의 레지스트리가 해당 객체가 파괴되지 않도록 할 수 있습니다.

모든 클래스를 수정할 수 있으면 모든 인스턴스를 추적하고 인스턴스의 소멸자가 정적 멤버에서 자신을 제거하도록 정적 멤버를 삽입 할 수 있습니다. 처리하는 경우 등

class InstanceRegistry { 
protected: 
    InstanceRegistry() { 
     registry.insert(this); 
    } 
    ~InstanceRegistry() { 
     registry.remove(this); 
    } 
private: 
    static SomeContainerType<InstanceRegistry*> registry; 
}; 

추가 작업이 클래스의 다른 유형에 대해 다른 레지스트리를 원하는 경우 수행 될 필요가있을 것이다,

+0

저는 COM을 사용하지 않고 있으며 객체의 단락/소멸자에 무언가를 추가하여 추가 할 수 있습니다. 목록 probs 개체에 대한 참조가 없어야합니다. –

+0

COM은 IRefCounted가 아닌 IUnknown을 사용합니다. –

+0

감사합니다. COM 메모가 삭제되었습니다. –

1

: 예를 들어, 다음과 같은 기본 클래스 또는 유틸리티 클래스를 사용할 수 있습니다 동일한 DLL을 사용하는 경우 각 프로세스는 해당 DLL의 정적 (또는 "전역") 데이터의 자체 복사본을 가져옵니다.

목록을 DLL의 전역 변수로 만들고 모든 응용 프로그램에서 해당 DLL에 연결하기 만하면됩니다. 그렇게하면 주변에 아무 것도 전달할 필요가 없습니다.

다중 DLL 프로세스에서 개체가 파괴되는 순서를 예측할 수 없기 때문에 목록의 파괴를 트래핑하는 것이 어려워집니다.

main 또는 WinMain 기능이 끝나면 목록의 내용을 덤프하는 것이 훨씬 간단합니다.

스마트 포인터 클래스를 일관된 방식으로 사용하지 않는 경우 그렇게하십시오. 또한 순환 참조 카운트를 찾아 볼 가치가 있습니다. 오브젝트 A는 오브젝트 B에 대한 카운트를 가지며, 반대표입니다. 이는 출시되지 않은 개체의 일반적인 원인입니다.

업데이트 :

실행하고 객체를 해제 할 모든 정적 소멸자를 강제로, 그래서 당신은 당신은 당신의 응용 프로그램 특정 방법을 구성해야합니다, 나중에 목록의 항목을 검사 할 수 있습니다.

프로세스를 시작하는 EXE가 매우 작다고 가정하고 실제로 모든 작업을 수행하는 다른 DLL을로드합니다. 이 다른 DLL은 LoadLibrary로로드됩니다. 어쩌면 (아마도 COM 또는 COM과 유사한 시스템으로). LoadLibrary API는 DLL을 프로세스로로드하거나 DLL이 이미로드 된 경우 내부 참조 카운터를 증가시켜 작동합니다. FreeLibrary API는 카운터가 0에 도달 할 때까지 카운터를 줄인 다음 DLL을 언로드합니다 (DLL의 정적 소멸자가 실행될 시점).

여기에 모든 미결 참조 된 개체의 목록을 포함하는 진단 DLL을 추가합니다. 다른 모든 DLL은 진단 DLL에 가져 오기 - lib 연결을 사용하며 EXE는 LoadLibrary도 사용합니다.

main이 끝나면 EXE는 이전에로드 한 DLL 핸들 목록을 검토하고 모두에 대해 FreeLibrary를 호출합니다. 진단 DLL이로드 된 상태로두면 진단 DLL이 끝까지 유지됩니다. 그것은 적어도 이론입니다.

하지만 다른 DLL을 언로드해야하는 순서는 무엇입니까? A.DLL에 B.DLL에 정의 된 객체에 대한 정적 포인터가있는 경우 먼저 A를 먼저 언로드해야합니다. 따라서 다양한 DLL이 어떻게 "계층화 된"아키텍처를 형성하는지에 대한 아이디어가 필요합니다. 하위 계층에 따라 상위 계층이 달라 지므로 안전한 순서로 언로드 할 수 있습니다.

또한 모든 DLL을 언로드 한 후에는 DLL의 개체를 참조하는 진단 목록의 항목이 이제 힙의 유효한 데이터를 가리키고 있지만 vtable은 정의 된 코드를 가리키고 있습니다 이제는 언로드 된 DLL로 인해 해당 객체에서 가상 함수를 호출 할 수 없게됩니다. 그래도 데이터를 검토 할 수 있어야합니다.

+0

winmain의 끝에서 목록을 덤프하는 문제는 정적 또는 전역 스마트 포인터에는 여전히 refrences가 있습니다.이 포인터는 파괴되었을 때 개체를 릴리스하므로 완벽하게 안전합니다. 따라서 스마트 포인터가 파손 된 후이 목록의 상태를 확인해야합니다. –

+0

정적 변수와 전역 변수의 99 %가 .exe 모듈에 있으며, 목록 이후에 여전히 언로드 된 것으로 나타났습니다. –

+0

나는 DLL로 애플 리케이션을 구축하고 목록을 포함하는 호스트 exe를 가지고 있고, 애플 리케이션을로드하고, WinMain을 호출 한 다음, WinMain이 리턴 할 때리스트를 언로드하고 덤프 할 수 있다고 생각한다. –