Fuite de mémoire WPF RichTextBox
-
06-07-2019 - |
Question
Dans mon application, de nombreux RichTextBox sont créés de manière dynamique au moment de l'exécution. J'ai réalisé que l'application présentait une fuite de mémoire, provoquée par les contrôles RichTextBox. Pour prouver que la mémoire fuit à cause du contrôle, j’ai écrit la méthode de test suivante:
for (int i = 0; i < 3000; i++)
{
Control rich = new RichTextBox();
pnl.Content = rich;
}
GC.Collect();
GC.WaitForPendingFinalizers();
pnl est un ContentControl déclaré dans le code Xaml.
Si vous exécutez le code suivant, vous pouvez constater que l’utilisation de la mémoire augmente rapidement.
Des idées pour résoudre le problème? J'ai envisagé de créer un pool d'objets, mais cela compliquerait mon application et je l'éviterais plutôt.
Modifier : j'ai ajouté un appel au ramasse-miettes pour démontrer que les objets ne sont pas ramassés. Il n'y a aucune amélioration de l'utilisation de la mémoire avec et sans l'appel de la méthode de collecte du GC.
Notez que l'appel de rich.Dispose
dans la boucle élimine la croissance de l'utilisation de la mémoire.
La solution
Je l'ai trouvé ailleurs, et cela semble être correct en ce qui concerne mes tests.
Quand un FlowDocument est créé, mise en forme relativement coûteux les objets de contexte sont également créés pour dans son StructuralCache. Lorsque vous créer plusieurs FlowDocs dans un environnement restreint boucle, un StructuralCache est créé pour chaque FlowDoc. Laisse vous appelé Gc.Collect à la fin de la boucle, dans l'espoir de récupérer de la mémoire. StructuralCache a un finaliseur libère ce contexte de formatage, mais pas immédiatement. Le finaliseur programme efficacement une opération pour libérer les contextes à DispatcherPriority.Background.
Ainsi, RichTextBox (ou FlowDocument) au cas où il ne fuit pas ne fait qu'attendre le nettoyage d'un thread en arrière-plan. Quand ça court exactement qui sait. Je souhaite que cela vienne de mettre en place une méthode d'élimination qui forcerait immédiatement le nettoyage.
Autres conseils
Cela ne signifie pas que votre application a une fuite de mémoire, mais bien que votre application utilise beaucoup de mémoire . C’est une fuite si les contrôles RichTextBox
ne sont pas libérés à un moment donné après qu’ils sont tombés hors de portée (la détection des fuites de mémoire sur les objets gérés est notoirement difficile et impossible à démonter).
Une idée fausse répandue selon laquelle un objet tombé hors de la portée de son contenu le ramènera à la poubelle. Cela le rend admissible à collecter. L'objet peut théoriquement jamais être collecté jusqu'à la fin de l'application. Le fait qu’il croisse avec RichTextBox
et non avec d’autres contrôles n’indique pas qu’il existe une fuite de mémoire dans RichTextBox
, cela indique simplement qu’il utilise plus de mémoire par jour. exemple que d’autres contrôles. Bien que ces informations puissent être utiles, elles ne vous aideront pas à déterminer s’il existe ou non une fuite de mémoire.
Nous avons eu le même problème dans Winforms 2.0 et nous avons dû acheter un contrôle de texte enrichi tiers. Je suppose que Microsoft n’a pas pris la peine de le réparer ...
Cela a corrigé le problème: http://blingcode.blogspot.com/2010/10 /memory-leak-with-wpfs-richtextbox.html
Ajoutez en gros deux attributs à chaque RichTextBox :) :) IsUndoEnabled = " False "
En ce qui concerne votre modification:
Vous avez ajouté les appels GC après la fin de la boucle et la création de 3 000 RichTextBox
Bien que je convienne qu'il semble étrange que la précédente ne soit pas libérée dans la boucle lorsqu'elle est remplacée par une nouvelle, c'est une boucle si serrée que le GC n'obtient probablement pas l'occasion de "faire des choses". ; avant la fin de la boucle.
Je ne pense pas que ce soit une bonne idée (mais cela devrait aller dans le code de test), mais avez-vous essayé de déplacer les appels du GC dans la boucle?