J'utilise Delphi 2009 qui a le gestionnaire de mémoire FastMM4 intégré à celui-ci. P>
Mon programme lit et traite un vaste ensemble de données. Toute la mémoire est libérée correctement chaque fois que j'effectue le jeu de données ou quittez le programme. Il n'a pas de fuite de mémoire du tout. p>
Utilisation de la routine actuelleMemorySusage donnée dans la réponse de Spenwarr à: Comment obtenir la mémoire utilisée par un programme Delphi , j'ai affiché la mémoire utilisée par FASTMM4 pendant le traitement. P>
Qu'est-ce qui semble se produire est que la mémoire est utilisée augmente après chaque cycle de processus et de libération. E.g.: P>
1,456 kb utilisé après le démarrage de mon programme sans jeu de données. P>
218,455 KB utilisée après avoir chargé un gros jeu de données. P>
71 994 kb après avoir nettoyé complètement le jeu de données. Si je sors à ce stade (ou à tout point de mon exemple), aucune fuite de mémoire n'est rapportée. P>
271,905 KB utilisée après avoir chargé le même jeu de données à nouveau. P>
125,443 kb après avoir effacé le jeu de données complètement. P>
325.519 KB utilisée après avoir chargé le même jeu de données à nouveau. P>
179,059 KB après avoir effacé le jeu de données complètement. P>
378,752 KB utilisée après avoir chargé le même jeu de données à nouveau. P>
Il semble que l'utilisation de la mémoire de mon programme augmente d'environ 53 400 kb à chaque cycle de charge / claire. Manager de tâches confirme que cela se produit réellement. P>
J'ai entendu dire que FastMM4 ne libère pas toujours toute la mémoire du programme au système d'exploitation lorsque des objets sont libérés de manière à empêcher une certaine mémoire quand elle en a besoin. Mais cette croissance continue me dérange. Étant donné qu'aucune fuite de mémoire n'est rapportée, je ne peux pas identifier un problème. P>
Est-ce que quelqu'un sait pourquoi cela se produit, si c'est mauvais, et s'il y a quelque chose que je peux ou devrait faire à ce sujet? P>
Merci Dthorpe et Mason pour vos réponses. Tu me as pensé et essayer des choses qui m'ont fait comprendre que je manquais quelque chose. Un débogage si détaillé était requis. P>
Comme il s'avère, toutes mes structures étaient correctement libérées à la sortie. Mais la libération de la mémoire après chaque cycle pendant la course n'était pas. Il accumulait des blocs de mémoire qui aurait normalement provoqué une fuite qui aurait été détectable à la sortie si mon nettoyage de sortie n'était pas correct - mais c'était. p>
Il y avait des stringlistes et d'autres structures dont j'avais besoin pour effacer entre les cycles. Je ne sais toujours pas comment mon programme a fonctionné correctement avec les données supplémentaires toujours là-bas des cycles précédents, mais elle l'a fait. Je vais probablement rechercher cela plus loin. P>
Cette question a été répondue. Merci pour votre aide. P>
4 Réponses :
L'utilitaire actuelMemorySusage que vous avez lié à la taille du jeu de travail de votre application. L'ensemble de travail est le nombre total de pages d'espace d'adresses de mémoire virtuelle mappée sur les adresses de mémoire physique. Cependant, certaines de ces pages peuvent avoir de très peu de données réelles stockées dans elles. L'ensemble de travail est donc la "limite supérieure" de la quantité de mémoire que votre processus utilise. Il indique à quel point l'espace d'adressage est réservé à l'utilisation, mais cela n'indique pas le montant réellement engagé (résidant en mémoire physique) ou la quantité de pages engagées est réellement utilisée par votre application. P>
Essayez ceci: après avoir été suivi de votre taille de travail de travail après plusieurs essais, minimisez la fenêtre principale de votre application. Vous verrez probablement la taille de la taille de travail chute de manière significative. Pourquoi? Étant donné que Windows effectue un appel SetProcessWorantSetSetSetSIsize (-1) lorsque vous minimisez une application qui élimine les pages inutilisées et rétrécit le jeu de travail au minimum. Le système d'exploitation ne fait pas cela pendant que la fenêtre de l'application est normale de taille normale car la réduction de la taille de jeu de travail peut trop forcer les performances en forçant les données à recharger à partir du fichier d'échange. P>
Pour y entrer plus en détail: votre application DELPHI attribue la mémoire dans des chunks assez petits - une chaîne ici, une classe là-bas. L'allocation de mémoire moyenne pour un programme est généralement inférieure à quelques centaines d'octets. Il est difficile de gérer de petites allocations comme cela efficacement sur une échelle à l'échelle du système. Le système d'exploitation ne le fait pas. Il gère les gros blocs de mémoire efficacement, en particulier sur la taille de la page de mémoire virtuelle 4K et la plage d'adresses de mémoire virtuelle 64K. P>
Ceci présente un problème pour les applications: les applications allouent généralement de petits morceaux, mais la mémoire des Doles OS dans des morceaux assez importants. Ce qu'il faut faire? Réponse: cédez. P>
Le gestionnaire de mémoire de la bibliothèque Delphi Runtime et le gestionnaire de mémoire de remplacement FastMM (et les bibliothèques d'exécution de toutes les autres langues ou outils de la planète) existent tous deux pour faire une chose: gravir les gros blocs de mémoire du système d'exploitation en blocs plus petits utilisé par l'application. Garder une trace de l'endroit où tous les petits blocs sont, à quel point ils sont gros et qu'ils ont été «fui» nécessitent une mémoire aussi bien - appelée des frais généraux. P>
Dans les situations d'allocation de mémoire intense / distribution, il peut y avoir des situations dans lesquelles vous avez annoncé 99% de ce que vous avez alloué, mais la taille de jeu de travail du processus ne réduit que 50%. Pourquoi? Le plus souvent, cela est causé par la fragmentation du tas: un petit bloc de mémoire est toujours utilisé dans l'un des grands blocs que le gestionnaire de mémoire Delphi obtenu à partir du système d'exploitation et divisé en interne. Le nombre interne de la mémoire utilisée est petit (300 octets, disons) mais comme il empêche le gestionnaire de tas de libérer le gros bloc que c'est dans le système d'exploitation, la contribution de ce petit morceau de 300 octets est plus comme 4K (ou 64k selon que ce soit des pages virtuelles ou des espaces d'adresses virtuels - je ne peux pas vous rappeler). p>
Dans une option intensive de mémoire lourde impliquant des mégaoctets de petites allocations de mémoire, la fragmentation du tas est très courante - en particulier si les allocations de mémoire pour les choses qui ne sont pas liées à l'opération intensive de la mémoire se déroulent en même temps que le gros travail. Par exemple, si vous craignez via votre opération de base de données de 80 Mo émet également de l'état sur une liste de liste, car il progresse, les chaînes utilisées pour signaler seront dispersées dans le tas de blocs de mémoire de base de données. Lorsque vous relâchez tous les blocs de mémoire utilisées par le calcul de la base de données, les chaînes de la liste de la liste sont toujours là (en cours d'utilisation, non perdues) mais elles sont dispersées partout, occupant potentiellement un grand bloc d'exploitation pour chaque petite chaîne. p>
Essayez le tour de la fenêtre minimiser pour voir si cela réduit votre ensemble de travail. Si tel est le cas, vous pouvez escompter la "sévérité" apparente des chiffres renvoyés par le comptoir de travail. Vous pouvez également ajouter un appel à SetProcessworkingSetSexize après votre grande opération de calcul pour purger les pages qui ne sont plus utilisées. P>
Il ne devrait pas voir que beaucoup de mémoire perdue à la fragmentation du tas. FastMM est spécialement conçu pour maintenir la fragmentation à un minimum absolu.
Oui, je suis au courant du design de FastMM. J'ai aidé à critiquer sa mise en œuvre et à l'obtenir dans le produit Delphi. Fastmm est toujours susceptible de surestimer la taille du travail.
Merci mais le minimisation avait un effet minimal et n'a pas corrigé le problème. J'ai également essayé la routine de nettoyage de la mémoire de Gabr à: Stackoverflow.com/questions/2031577/CAN-Memory-be-Cleaned-up / ... et cela n'a pas aidé non plus. p.s. La réponse de Barry Il y a très informatif.
Quel type de jeu de données utilisez-vous? Si cela est implémenté complètement à Delphi (ne pas appeler à un autre code avec un autre gestionnaire de mémoire, comme Midas, vous pourriez essayer de fuir délibérément le jeu de données. P>
Je suppose que votre ensemble de données est sur une forme, et il est libéré automatiquement lorsque le formulaire efface ses composants. Essayez de mettre myDataset: = nil; code> dans votre formulaire OnDestroy. Cela garantira que le jeu de données fuit et tout ce que le jeu de données est propriétaire. EM> Essayez cela après avoir chargé une fois de chargement une fois de chargement et comparez les rapports de fuite, et voyez si cela vous donne quelque chose d'utile. < / p>
@ Mason: Peut-être que mon terme "DataSet" est trompeur. Par jeu de données, je veux dire un fichier d'entrée basé sur un texte ou unicode d'une taille de grande taille que je lis en tant que filtream, ainsi que les structures de données internes que j'en ai créées. Je n'utilise pas une base de données. Mon programme est un seul exe. Je n'appelle aucune DLL externe. Ma suspicion, en raison de la grande taille du morceau de la mémoire perdue, qu'il a quelque chose à voir avec ce filtream et peut-être que le tampon que je charge. Mais aucune fuite n'est signalée soit par Eurekalog ou par AQTime. Je suis dans de lourd débogage maintenant.
Vous êtes une mémoire à moitié fuite; de toute évidence. Vous fuyez la mémoire lorsque le programme est en cours d'exécution, mais lorsque vous fermez le programme, votre ensemble de données est correctement libéré de sorte que FastMM (à juste titre) ne le signalez pas. P>
Voir ceci pour plus de détails: Mon programme ne libère jamais la mémoire. Pourquoi? p>
Vous pouvez utiliser vmmap pour tracer les octets les plus alloués. Cela m'a aidé à un scénario similaire.
Lorsque l'application s'ouvre, VMMAP tracera toutes la mémoire allouée et libérée à l'aide de détours dans les méthodes d'allocation / libre. Vous pouvez voir dans le bouton de timeline (sur le Botton de VMMAP) la chronologie de la mémoire (évidemment). P>
Cliquez sur le bouton Trace. Il montrera toutes les opérations d'allocations / de transcommandes dans le temps tracé. Commandez les octets de colonne de montrer d'abord le plus d'octets et double-cliquez dessus. Il montrera la CallStack de l'allocation. Dans mon cas, le premier élément a montré mon problème. P>
échantillon app: p> Lorsque vous cliquez sur la touche une fois, et voir la trace dans vmmap, Affiche: P> et la pipetack: p> Dans ce cas n'a pas montré exactement le code, mais le vl.controls.tcontrol.click donne une idée. Dans mon vrai scénario, aidé davantage. P> Il y a beaucoup d'autres fonctionnalités dans VMMAP qui aide à analyser les problèmes de mémoire. P> p>
IMHO, vous auriez dû ajouter votre réponse et l'accepté au lieu de modifier la question. Il est plus facile de rechercher quelqu'un pour trouver la question, la réponse et apprendre de votre expérience.