1
votes

Fuite de mémoire dans la zone de liste déroulante Windows Forms depuis .Net Framework 4.8

Nous sommes passés de .NET Framework 4.6 à 4.8 il y a quelques semaines. Depuis ce temps, nous avons une fuite de mémoire qui est causée par le .NET Framework lui-même.

.NET Framework 4.8 utilise le niveau 3 des fonctionnalités d'accessibilité. Dans le cas de la zone de liste déroulante ItemAccesssibleObjects , cela signifie que la propriété System.Windows.Forms.ComboBox.AccessibilityObject contient un objet d'une sous-classe interne System.Windows.Forms.ComboBox.ComboBoxUiaProvider qui a la propriété interne ItemAccesssibleObjects , qui est un dictionnaire qui contient tous les éléments qui ont été ajoutés à cette combobox, jamais.

Ainsi, même si vous effacez les éléments de la zone de liste déroulante, ce dictionnaire interne a toujours une référence à l'élément. Donc, tous les éléments qui ont été ajoutés à la liste déroulante sont cumulés ... C'est une fuite de mémoire.

J'ai un échantillon à part entière sur GitHub qui montre l'effet.

Si le projet est rétabli à .NET Framework 4.6, la fuite de mémoire n'existe pas car une autre sous-classe de System.Windows.Forms.ComboBox.AccessibilityObject sera utilisée.

Je suppose que je peux "résoudre" ce problème en désactivant les fonctionnalités d'accessibilité de niveau 3 de .NET Framework 4.8, mais c'est une trop mauvaise solution à mon avis.

Bien sûr, je suppose que je peux utiliser la réflexion pour résoudre ce problème (supprimer l'élément du dictionnaire interne), mais je n'aime pas non plus cette option car ce sont des éléments internes et peuvent changer à l'avenir ...

Quelqu'un connaît-il ce problème / existe-t-il déjà une bonne solution disponible?

Merci


0 commentaires

3 Réponses :


0
votes

Une solution possible serait:

  • pour remplacer la classe ComboBox par la vôtre: disons OwnComboBox .
  • pour remplacer la fonction CreateAccessibilityInstance() et conserver dans la classe surchargée la référence au ComboBoxUiaProvider ( AccessibleObject ) créé par la fonction de base (attention, cela peut être autre chose que ComboBoxUiaProvider ).
  • pour remplacer la fonction Dispose(bool disposing) et nettoyer manuellement le dictionnaire interne.

Lien qui pourrait aider: code ComboBox .


0 commentaires

0
votes

Une solution pourrait être:

  • pour remplacer la classe ComboBox par la vôtre: disons OwnComboBox .
  • pour remplacer la fonction Dispose(bool disposing) this.WndProc(NativeMethods.WM_NCDESTROY) Dispose(bool disposing) et exécuter cet appel: this.WndProc(NativeMethods.WM_NCDESTROY) .

Lien qui pourrait aider: code ComboBox .


2 commentaires

Je n'ai pas la possibilité de sous-classer combobox puisque le contrôle combobox est généré à partir d'un contrôle de barre ruban qui ne permet pas ce niveau de contrôle.


Peut-être que vous pouvez également sous-classer la barre de ruban pour remplacer la fonction qui renvoie la zone de liste déroulante?



0
votes

Nous avons un problème très similaire. UserObjects et GDIObjects fuient après la mise à niveau de .net 4.6 vers 4.8. Il n'est visible que lorsque nous exécutons des tests de fuite de mémoire via des outils d'automatisation. Lorsque vous cliquez manuellement ou si nous modifions le code interne pour appeler simplement les gestionnaires de clic de bouton qui parcourent les formulaires et les ferme, il n'y a pas de fuite de mémoire.

Ajouter ceci à app.config

<runtime>
    <AppContextSwitchOverrides value="Switch.UseLegacyAccessibilityFeatures=false;Switch.UseLegacyAccessibilityFeatures.2=false;Switch.UseLegacyAccessibilityFeatures.3=true"/>
</runtime>

nous l'avons résolu, mais nous avons réalisé que nous ne pouvions pas exécuter notre application en mode débogage ou qu'il y avait des erreurs étranges.

Nous avons découvert que si toutes les combobox sont supprimées de la vue, il n'y a pas de fuite de mémoire. Le problème est donc à 100% dans Combobox. Nous avons essayé les deux réponses de Bioukh et celle avec Dispose a fonctionné ... mais plus tard, j'ai vérifié et il n'était pas nécessaire de remplacer ComboBox. Le problème auquel nous avons été confronté était dû au fait de ne pas supprimer les ComboBox lors de leur suppression dynamique de la vue.

Notre problème était que nous réutilisions la vue. Nous supprimons les ComboBox de la vue, puis nous en ajoutons de nouvelles sans supprimer les anciennes. Apparemment, GC ne les élimine pas automatiquement ou il y a quelque chose qui les tient (j'ai essayé mais je n'ai rien trouvé).

Le correctif était - avant de les supprimer, nous faisons une copie de la liste, les supprimons de la vue, puis supprimons chaque élément de la liste. La fuite de mémoire a disparu maintenant. Voici un lien vers la documentation sur la suppression de contrôles d'une collection par programme


0 commentaires