2009-04-11 3 views
2

J'ai un certain nombre de classes comptées de référence dans certaines de mes applications, et aussi dans les dll que ces applications utilisent, toutes héritant et implémentant une interface IRefCounted.C++: Débogage de fuites de mémoire dans le système de comptage de références

Afin d'aider à trouver la source de ces fuites de mémoire, je veux que chaque application maintienne une liste de toutes ces classes comptées de réfrence en existence. Le problème est la gestion des instances de ces listes de sorte que leur utilisation n'affecte pas l'utilisation de mes classes (par exemple, je n'ai pas besoin de passer un pointeur sur une liste tout le temps, au lieu de l'attacher à le processus).

-Therees une bonne chance que plusieurs de ces applications peuvent être en cours d'exécution à la fois, et en utilisant la même DLL. Chaque application a besoin de sa propre liste d'objets, et toutes les DLL chargées par cette application doivent utiliser cette liste (mais rappelez-vous qu'une DLL peut être chargée par plusieurs applications ...).
-La liste doit être détruite après chaque autre variable globale et statique dans l'application, de sorte que les objets laissés dans la liste lorsqu'ils sont détruits sont ceux qui n'ont pas été libérés correctement. Je vais simplement ajouter un point d'arrêt au destructeur de la liste afin que je puisse regarder à travers les objets non alloués dans le débogueur.

+0

Désolé, quelle est votre question? –

Répondre

1

Je suppose que vous utilisez COM. Vous aurez probablement besoin de trouver un moyen d'avoir un weak pointer de sorte que le registre des objets instanciés n'empêche pas qu'ils soient détruits.

Si vous pouvez modifier toutes les classes, vous pouvez injecter un membre statique pour garder une trace de toutes les instances et demander au destructeur d'une instance de se retirer du membre statique. Par exemple, vous pouvez utiliser une classe de base ou une catégorie d'utilitaire comme les suivantes:

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

travail supplémentaire devrait être fait si vous voulez un registre différent pour différents types de classes, etc.

+0

Je n'utilise pas COM, et je pourrais ajouter quelque chose au con/destructor des objets pour ajouter les retirer de la liste. Les probs de liste ne devraient pas avoir un ref aux objets. –

+0

COM utilise IUnknown, pas IRefCounted. –

+0

Merci. La note COM a été supprimée. –

1

Si les processus utilisent la même DLL, chaque processus obtient sa propre copie privée des données statiques (ou "globales") de cette DLL.

Tout ce que vous devez faire est de faire de la liste une variable globale dans une DLL, et de la lier à cette DLL à partir de chaque application. De cette façon, il n'y a pas besoin de passer quelque chose de plus.

Votre idée de piéger la destruction de la liste est lourde de difficultés, en raison de l'imprévisibilité de l'ordre de destruction des objets dans un processus multi-DLL.

Il serait beaucoup plus simple de vider le contenu de la liste à la fin de la fonction main ou WinMain.

Si vous n'utilisez pas une classe de pointeurs intelligents de manière cohérente, faites-le. En outre, il peut être utile de rechercher des comptes de référence cycliques - l'objet A compte sur l'objet B et vice versa. C'est une cause commune d'objets inédits.

Mise à jour:

Pour forcer tous les statiques pour exécuter Destructeurs et libérer des objets, de sorte que vous pouvez ensuite examiner les entrées dans la liste après, vous aurez besoin de structurer votre application d'une certaine façon.Supposons que vous ayez un EXE très minimal qui lance le processus et charge un certain nombre d'autres DLL qui font tout le travail. Ces autres DLL sont chargées avec LoadLibrary, en quelque sorte (peut-être par COM ou un système COM-like). L'API LoadLibrary fonctionne soit en chargeant la DLL dans le processus, soit en incrémentant un compteur de référence interne sur la DLL si elle est déjà chargée. L'API FreeLibrary décrémente le compteur jusqu'à ce qu'il atteigne zéro, puis décharge la DLL (à quel point les destructeurs statiques de cette DLL s'exécuteront). Pour cela, nous ajoutons maintenant notre DLL de diagnostic qui contient une liste de tous les objets comptés de référence en suspens. Toutes les autres DLL utilisent le lien import-lib vers la DLL de diagnostic, et le fichier EXE utilise également LoadLibrary.

Lorsque main est sur le point de quitter, le fichier EXE parcourt la liste des handles DLL qu'il a précédemment chargés et appelle FreeLibrary sur chacun d'eux. En gardant le DLL de diagnostic chargé, il s'assure qu'il est toujours là à la fin. C'est la théorie au moins.

Mais dans quel ordre les autres DLL doivent-elles être déchargées? Si A.DLL a des pointeurs statiques vers des objets définis dans B.DLL, il vaut mieux d'abord décharger A. Vous devez donc avoir une idée de la façon dont vos différentes DLL forment une architecture «en couches», avec des couches plus élevées en fonction des couches inférieures, vous donnant ainsi un ordre sûr pour les décharger. De plus, une fois que vous avez déchargé toutes les DLL, toutes les entrées de la liste de diagnostic qui font référence aux objets dans les DLL pointeront maintenant vers des données valides sur le tas, mais la vtable pointera sur le code qui a été défini par les DLL qui ont maintenant été déchargées, donc vous ne serez pas en mesure d'appeler des fonctions virtuelles sur ces objets. Vous devriez être en mesure d'examiner leurs données si.

+0

Le problème avec le dumping de la liste à la fin de winmain est que tous les pointeurs intelligents statiques ou globaux auront toujours des réfrences, ce qui est parfaitement sûr car ils vont libérer l'objet quand ils sont détruits. Donc j'ai vraiment besoin de voir l'état de cette liste après que de tels pointeurs intelligents ont été détruits. –

+0

Fin, sauf que 99% des variables statiques et globales sont dans le module .exe, qui semble toujours être déchargé après la liste. –

+0

Je suppose que je pourrais construire les applications en tant que DLLs, et avoir un exe hôte qui contient la liste, charge l'application, appelle WinMain dans cette application, puis décharge et vide la liste lorsque WinMain revient? –

Questions connexes