10
votes

Libérer la mémoire allouée dans une DLL différente

J'ai un fichier EXE à l'aide d'un fichier DLL qui utilise un autre fichier DLL. Cette situation est arise:

dans le fichier DLL 1: xxx

dans le fichier DLL 2: xxx

in libération mode, tout fonctionne bien. Mais dans le mode de débogage, je propose une défaillance d'affirmation dans le destructeur de l'un des std :: cordes dans le vecteur des dossiers (lorsque les dossiers sont hors de portée à la fin de l'acconction):

dbgheap.c: ligne 1274 xxx

Je suppose que c'est parce que la mémoire a été allouée sur le tas de fichiers DLL 1, mais est en cours de libération dans le fichier DLL 2.

Le commentaire dans dbgheap.c semble assez insistant que ceci est un problème.

Pourquoi ce problème est-il un tel problème, quand il semble fonctionner bien si je l'ignore juste? Existe-t-il une façon de faire cela?


2 commentaires

NE PAS. Ignorer. CE. C'EST. POURQUOI. J'AI DEMANDÉ. = P


Je veux juste savoir pourquoi c'est un problème.


4 Réponses :


8
votes

Très probablement, la construction de la libération a le même problème, mais les constructions de libération n'entraînent pas. Ils ignorent juste le problème. Vous ne pouvez jamais voir un problème. Ou vous pouvez voir la corruption des données. Ou vous pourriez voir un crash. Peut-être que seuls vos utilisateurs expérimenteront des bugs que vous n'êtes tout simplement pas capable de reproduire.

Ne pas ignorer les affirmations CRT.

Vous devez toujours utiliser le récipient appropriéLocator (celui qui correspond à l'allocateur utilisé pour commencer). Si vous utilisez des bibliothèques Static CRT dans vos fichiers DLL, les fichiers DLL utilisent différents tas. Vous ne pouvez pas distribuer la mémoire sur des tas. Allouer et annoncer un bloc de mémoire en utilisant le même tas.

Si vous utilisez des bibliothèques CRT partagées dans vos fichiers DLL, ils doivent utiliser le même tas et vous pouvez allouer dans un fichier DLL et traiter dans une autre.



14
votes

Comme Sean l'a déjà dit, la version de sortie ignore simplement cette déclaration de suppression, de sorte que le mieux que vous puissiez espérer est une fuite de mémoire.

Si vous contrôlez comment les deux fichiers DLL sont compilés, assurez-vous d'utiliser les paramètres DLL DLL (/ MDD) multi-threads ou multi-threads (/ MD) pour la bibliothèque d'exécution. De cette façon, les deux fichiers DLL utiliseront le même système d'exécution et partageront le même tas.

L'inconvénient est que vous devez installer le système d'exécution avec votre application (Microsoft propose un installateur pour cela). Cela fonctionnera bien sur votre machine de développement car Visual Studio installe également que le système d'exécution également, mais sur une machine fraîchement installée, il signalera les fichiers DLL manquants.


1 commentaires

Mes propriétés du projet ont eu tort - je n'ai pas eu de débogage de DLL (/ MDD), cela fonctionne maintenant bien. Merci!



5
votes

Ce n'est qu'un problème si l'application ou une (ou plusieurs) des fichiers DLL est liée à la version statique de la bibliothèque standard. Cela a été résolu il y a une décennie par MS libérant la version de la bibliothèque partagée de la bibliothèque standard. En effet, chaque version de la bibliothèque standard construit son propre tas interne et ainsi avec plusieurs tas, vous devez libérer la mémoire sur le tas correct. En utilisant la version partagée de la bibliothèque standard, ils utilisent tous le même tas.

Il s'agit d'une pratique standard de nos jours pour l'application et tous les fichiers DLL doivent être conçus pour utiliser la version dynamique de la bibliothèque standard.

La seule mise en garde à ce qui précède est si vous créez votre propre tas et allouer de la mémoire de ce tas. Mais il s'agit d'une procédure très spécialisée que dans des situations rares (et si vous comprenez suffisamment pour l'utiliser, vous ne serez pas dans la situation de poser cette question).


0 commentaires

7
votes

Comme autre dit, le problème peut être résolu en veillant à ce que le CRT soit partagé entre les deux modules. Mais il y a des scénarios communs où ce contrat est difficile à appliquer.

La raison est que la raison de s'assurer de créer un lien avec un CRT partagé ne fonctionnera pas si l'EXE et la DLL ne relient pas à la même version CRT (STRAND> (comme dans 6.0, 7,0, 8,0). Par exemple, si vous prenez une DLL qui a été construite en VC6.0 et essayez de l'utiliser avec une version EXE dans VS2010, vous obtiendrez le même problème qu'auparavant. Les deux versions de CRT seront chargées dans votre processus et utiliseront chacune leur propre tas pour une allocation, peu importe si votre EXE et votre DLL utilisent le CRT «partagé», ils ne seront pas les mêmes.

Une meilleure pratique pour une API serait de s'assurer que les objets alloués d'un côté sont également détruits du même côté. Je sais que cela sonne laid mais c'est le seul moyen de s'assurer qu'une DLL reste compatible binaire.


1 commentaires

Utiliserait la version polymorphe d'allocator de vecteur et string travail? Depuis qu'ils appellent la fonction d'allocation polymorphe, qui (potentiellement) pointerait vers le code à l'intérieur de la DLL?