2013-08-22 2 views
2

FastMM signale une fuite de mémoire (UnicodeString) pour l'extrait de code suivant qui utilise une variable de fil d'enregistrement avec une chaîne:FastMM rapports fuite de mémoire pour la variable de fil d'enregistrement

program Project10; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    FastMM4, 
    System.SysUtils; 

type 
    TContext = record 
    Value : String; 
    end; 

threadvar 
    Context : TContext; 

begin 
Context.Value := 'asdfsdfasfdsa'; 
end. 

Est-ce une vraie fuite de mémoire ou est nettoyage des variables de thread juste après que FastMM vérifie les fuites de mémoire?

Encore plus important: comment est-ce que je peux supprimer ces "fuites de mémoire" signalées car elles encombrent d'autres fuites de mémoire qui pourraient être trouvées?

+0

Je crois que le fil doit nettoyer les valeurs dynamiques? Essayez d'ajouter Context.Value: = '' dans le code de nettoyage du thread. – whosrdaddy

+0

Cela fait partie de mon code de journalisation, donc je ne peux pas contrôler le nettoyage des threads car cela peut être appelé à partir de n'importe quel thread. – jpfollenius

+3

Si vous n'avez pas accès aux threads, alors pourquoi utilisez-vous des variables de thread pour commencer? À quoi les utilisez-vous exactement? Puisque vous ne contrôlez pas les threads, le seul moyen que je connaisse pour détecter les terminaisons de thread est d'écrire et de charger une DLL afin de pouvoir recevoir les notifications 'DLL_THREAD_DETACH'. Mais alors la DLL devrait gérer la mémoire de variable de fil, à moins que vous ne partagiez FastMM à travers la frontière de DLL. –

Répondre

7

C'est une vraie fuite. Les variables locales de thread ne sont pas finalisées lorsqu'elles sont hors de portée. Étant donné que votre enregistrement contient un champ géré, le champ chaîne, la mémoire allouée par tas associée à cette chaîne est divulguée si l'enregistrement n'est pas finalisé.

Les documentation appelle cette explicitement:

variables dynamiques qui sont habituellement gérées par le compilateur (longues chaînes, des chaînes larges, des tableaux dynamiques, des variantes, et interfaces) peuvent être déclarées avec threadvar, mais le compilateur ne libère pas automatiquement la mémoire allouée par tas créée par chaque thread d'exécution. Si vous utilisez ces types de données dans des variables de thread, il est de votre responsabilité de disposer de leur mémoire à partir du thread, avant que le thread se termine.

Si vous souhaitez colmater la fuite, vous devrez finaliser la variable à la fin de la portée. C'est-à-dire que le thread se termine.

Finalize(Context); 

Notez que vous devez exécuter ce code du fil qui possède la variable puisque, de toute évidence, que ce fil a accès.

Si vous souhaitez supprimer le signalement de ces fuites, appelez RegisterExpectedMemoryLeak.

Si vous ne pouvez pas exécuter de code lorsque les threads se terminent, il peut être préférable d'éviter l'allocation de tas et d'utiliser un tableau de caractères de longueur fixe. Très probablement que vous répondez à vos besoins.

Il semblerait étrange que vous prétendez ne pas être en mesure d'exécuter du code lorsque les threads se terminent. Si vous ne pouvez pas faire cela, comment pouvez-vous exécuter du code dans le contexte de ces threads. En d'autres termes, pour qu'il y ait une fuite, vous devez avoir exécuté votre code dans ces threads.

+0

Salut David, s'il vous plaît voir mon commentaire à la question ... il me semble qu'il n'y a aucun moyen pour moi de savoir quand un thread se termine puisque je n'ai aucun contrôle de ces discussions. – jpfollenius

+0

Si vous voulez éviter ces fuites, vous devrez changer quelque chose à propos de votre design. J'ai ajouté quelques suggestions. –

+0

Je n'ai pas encore décidé quoi faire (RegisterExpectedMemoryLeak n'est pas une option car je ne sais pas combien de fuites dépendent du nombre de threads qui enregistrent quelque chose). Je vais laisser ma question ouverte pendant un certain temps pour que d'autres puissent aussi contribuer, après quoi j'accepterai une réponse. – jpfollenius

0

Créer un tableau global de TContext, puis stocker l'index de l'élément, qui appartient à votre thread, dans un threadvar.

+0

Cela ne répond pas vraiment à la question. Mais même ainsi, qu'allez-vous faire avec ce tableau global? Attendre jusqu'à la fin, puis finaliser tous les enregistrements? Dans ce cas, c'est exactement la même chose que RegisterExpectedMemoryLeak. Ou vouliez-vous faire quelque chose d'autre avec ce tableau. Oh, et évidemment l'accès au tableau doit être synchronisé. Ce qui nuirait à la performance. –

+0

Je ne pense pas qu'il soit nécessaire de synchroniser le tableau entier, car un seul élément sera modifié par thread. –

+0

@Fabricio Que se passe-t-il lorsqu'un nouveau thread est créé et que le tableau doit être redimensionné? –