6
votes

Lambdas au sein des extensions: future de mémoire possible?

Je viens de donner une réponse à un Question assez simple < / a> en utilisant une méthode d'extension. Mais après l'avoir écrit, je me suis souvenu que vous ne pouvez pas vous désabonner d'une Lambda d'un gestionnaire d'événements.

Jusqu'à présent, pas de gros problème. Mais comment tout cela se comporte-t-il dans une méthode d'extension ??

ci-dessous est mon code reniflé à nouveau. Alors, quelqu'un peut-il vous éclairer, si cela conduira à des myriades de minuteries suspendues à la mémoire si vous appelez cette méthode d'extension plusieurs fois plusieurs fois?

Je dirais non, car la portée de la minuterie est limitée dans cette fonction . Donc, après avoir laissé cela, personne d'autre n'a une référence à cet objet. Je suis juste un peu incertain, car nous sommes ici dans une fonction statique dans une classe statique. xxx

mise à jour

juste pour clarifier j'ai utilisé System.windows.Forms.ticer . Donc, de vos réponses, il semble que, notamment en utilisant cette classe de minuterie, était le bon choix parce que cela fait quelque chose comme je l'attends dans ce cas. Si vous essayez une autre classe de minuterie dans ce cas, vous pouvez rencontrer des ennuis comme Matthew a découvert . Aussi je trouvé un moyen en utilisant faiblesse S si mes objets restent vivants ou non.

Mise à jour 2

Après un peu de sommeil et un peu plus de pensée, j'ai également fait un autre changement à mon testeur ( Réponse ci-dessous ) Je viens d'ajouter un gc.collect () après la dernière ligne et définissez la durée sur 10000 . Après le démarrage du BlinkText () Plusieurs fois, j'attends tout le temps ma touche2 pour obtenir l'état actuel et forcer une collection à ordures. Et comme il semble que toutes les chronomètres seront détruits après appeler la méthode . Donc, aussi une collection de déchets tandis que mon blinktext est déjà laissé et que la minuterie est en cours d'exécution, ne pose aucun problème.

Donc, après toutes vos bonnes réponses et un peu plus de tests, je peux heureusement dire que ça fait Ce qu'il devrait sans laisser de minuteries dans la mémoire ni jeter les minuteries avant de faire leur travail.


3 commentaires

Votre code échouera sans distinction dû à l'appel de fil croisé illégal. Votre minuterie (spécifiquement le WinForms One) doit avoir un objet de synchronisation.


@Leppie: mal, cette minuterie utilise le messagePump. Essayez-le.


@HENK HOLTERMAN: Merci, il semble que je l'ai confus avec le system.timers.timer .


7 Réponses :


4
votes

Votre hypothèse est correcte. TIMER sera attribué lorsque la méthode est appelée et être éligible à la collecte des ordures à la fin.

Le gestionnaire d'événements Lamba (en supposant que ce n'est pas référencé ailleurs) sera également éligible à la collecte des ordures.

Le fait qu'il s'agisse d'une méthode statique et / ou d'une méthode d'extension ne modifie pas les règles de base de l'accessibilité de l'objet.


2 commentaires

Cela pourrait-il signifier que si vous appelez GC.Collect avant la durée, cela pourrait entraîner une défaillance clignotante?


@Alxandr: Non, une minuterie active reste accessible, le GC ne le collectera pas.



0
votes

On dirait que la minuterie restera vivante jusqu'au début du programme. J'ai essayé de disposer de l'étiquette et de définir sa référence à NULL, mais la minuterie n'a pas été collectée avant d'avoir quitté le programme.


4 commentaires

Compilez pour libérer et forcer une collection.


Je l'ai fait mais ce n'est pas collecté.


Ouais, je me demandais simplement si cela serait nettoyé. Je suppose que le fait que la minuterie soit jetable. Quelque chose doit conserver une référence à l'objet de la minuterie, puis à nouveau, le fil pouvant traiter la boucle d'événement. Il est très possible que l'objet reste de rester en vie parce que la référence de l'événement. Alors oui, il y a beaucoup une fuite ici.


C'est bien de voir que les gens sont toujours en train de voter sans laisser de note.



2
votes

Les fuites de mémoire ne sont pas votre problème ici. Le collecteur des ordures peut disposer de l'objet de la minuterie. Mais pendant que la minuterie n'est pas arrêtée, il semble y avoir une référence à la minuterie, il n'est donc pas disposé prématurément. Pour vérifier cela, dérivez une classe Mytimer de la minuterie, déverrouiller le dispositif (BOOL) et définir un point d'arrêt. Après un appel de blinktext appel GC.Collect et GC.WAITFORPENDENDINAIRES. Après le deuxième appel, la première instance de minuterie est disposée.


1 commentaires

Je ne pouvais pas vérifier cela (avec un appel à gc.collect directement après l'appel à Blinktext).



1
votes

Je viens de faire un test amusant dans le sens de ce que @ Cornerback84 disait. J'ai créé un formulaire avec une étiquette et deux boutons. Un bouton lié votre méthode d'extension, l'autre liaison A Forced gc.collect () . J'ai ensuite supprimé le Timer.stop () dans votre boucle d'événement. C'était vraiment amusant de cliquer plusieurs fois sur le bouton de démarrage. L'intervalle du clignotement a été assez mélangé.

Il semble qu'il y a une fuite de mémoire / de ressource ici ... mais à nouveau, la minuterie est un objet jetable qui n'est jamais disposé.

EDIT: ...

Laissez le plaisir de commencer ... Cela peut également dépendre de la minuterie que vous utilisez.

  • system.windows.forms.ticer => ceci ne collectera pas mais va travailler juste Fine avec la pompe à message système. Si vous appelez .stop () Cet objet pourrait devenir éligible pour collecter.

  • system.timers.timer => cela ne fait pas Utilisez la pompe à message. Vous aussi aussi appelez la pompe à message. Ce ne sera pas collecter. Si vous appelez .stop () Cet objet pourrait devenir éligible pour collecter.

  • system.threading.Timer => Ceci nécessite d'invoquer la pompe à message. Mais cela s'arrêtera également sur un gc.collect () (cette version ne semblait pas fuir)


7 commentaires

Ne pas disposer d'un état idéal n'est pas une fuite de mémoire. C'est juste inefficace.


@HENK: Cela peut beaucoup conduire à des fuites de mémoire et de ressources.


Matthew, un malentendu courant. Idisposables dont il a besoin d'avoir un destructeur (finaliseur). Le nettoyage est juste retardé.


@HENK: Le finaliseur n'est jamais appelé si quelque chose dans le système tient une référence à l'objet. Il existe également des objets qui mettent en œuvre Idisposable qui n'ont pas de finaliseurs (grâce aux auteurs de ces classes;). Il est également très possible que votre finisseur ne soit jamais appelé. Il est à 100% du GC de l'appeler. Et s'il n'obtient pas le travail suffisamment rapide, le GC pourrait tuer l'appel.


"Le GC pourrait tuer l'appel" - êtes-vous sûr? Pour le reste, voir Stackoverflow.com/Questtions/2101524/...


@HENK: Comment cela se rapporte-t-il? Il parlait d'utilisation du en utilisant la déclaration . MSDN.MicRosoft.com/en-us/Library/system. objet.finalize.aspx


Vous voudrez peut-être aussi consulter cette question (et ses réponses) Stackoverflow.com/Questtions/45036/...



3
votes

Votre code est correct et ne fuit pas la mémoire ni les ressources, mais seulement parce que vous arrêtez la minuterie de l'EventHandler. Si vous commencez le // minuterie.stop (); il restera sur clignotant, même lorsque vous faites un gc.collect (); plus tard.

La minuterie attribue une fenêtre à écouter pour les messages WM_ et est en quelque sorte ancré par cela. Lorsque la minuterie est arrêtée ( activé = false ), il libère cette fenêtre.
Le statique ou méthode d'extension ne joue pas de rôle.


2 commentaires

Juste parce que vous .STOP () Les minuteries ne sont pas éliminées par magicide. Le système tient toujours une référence à cet objet même s'il ne fait rien.


Je rétracte ce que j'ai dit. Vous cherchez plus près que system.windows.forms.ticer a la possibilité de libérer le gchandle lorsque vous appelez stop.



0
votes

Vous devez disposer de la minuterie explicitement en appelant sa méthode d'étalage ou implicitement en appelant l'arrêt après l'utilisation, votre implémentation est donc correcte et ne causerait jamais de fuites de mémoire.


0 commentaires

0
votes

Après avoir lu toutes vos réponses, je viens de trouver un moyen de mieux le tester.

J'ai mis à jour ma classe d'extension de la manière suivante: xxx

J'ai aussi créé une seconde Bouton, une deuxième étiquette et ajouté le code suivant à l'événement de clic: xxx

Je viens de reprocher le premier bouton plusieurs fois pour laisser clignoter la première étiquette. Ensuite, j'ai appuyé mon deuxième bouton et j'ai obtenu une liste où je peux voir si mes minuteries sont toujours vivantes. À un premier clic, ils ont tous un vrai. Mais ensuite, j'ai frappé mon premier bouton plusieurs fois à nouveau et quand j'ai mis à jour mon message d'état, j'ai vu que les premiers articles ont déjà une fausse in Isalive. Donc, je peux dire en toute sécurité que cette fonction ne conduise pas de problèmes de mémoire.


0 commentaires