Vorsichtsmaßnahmen treffen, um Speicherlecks aufgrund hinzugefügter Ereignishandles zu verhindern

8

Ich werde eine GUI erstellen, die dynamisch Steuerelemente mit zugeordneten Ereignissen erstellt. Ich muss diese Steuerelemente zur Laufzeit hinzufügen und entfernen. Es sieht so aus:

%Vor%

Ich habe gehört, dass das Zuweisen von Ereignishandlern mit + = zu Speicherlecks führen kann (spezifischer wird der Speicher erst freigegeben, wenn die Anwendung beendet wurde). Ich möchte das vermeiden. Ich weiß, dass ich einige Funktionen wie hier schreiben kann Wie alle Ereignisse zu entfernen Handler von einem Steuerelement , um alle Ereignishandler zu finden und zu entfernen, aber es sieht sehr komplex aus.

Gibt es einen anderen Weg? Hilft das Aufrufen von Dispose, diese Ereignisbehandlungsroutinen zu entfernen? Können Sie Objekte zerstören, um ihren Speicher wie in C / C ++ freizugeben?

Danke!

PS: Problem ist, ich weiß nicht, welches Ereignis zu lösen ist. Ich werde viele Labels erstellen und ihnen verschiedene Arten von onclick-Ereignissen hinzufügen. Wenn es Zeit ist, das Flow-Layout-Panel zu bereinigen, gibt es keine Möglichkeit zu wissen, welcher Event-Handler an welches Label angehängt wurde.

Dies ist der Beispielcode (_flowLP ist ein FlowLayoutPanel) - diese Refresh () - Funktion wird mehrmals ausgeführt, bevor die Anwendung beendet wird.

%Vor%     
Istrebitel 09.04.2012, 18:04
quelle

3 Antworten

3

Dies ist hauptsächlich eine Sorge, wenn Sie einen Event-Consumer mit kürzerer Lebensdauer an einen längerlebigen Event-Producer anhängen. Wenn sie ähnliche Leben haben oder das Gegenteil von dem sind, was ich beschrieben habe, ist das kein Problem.

Wenn Sie sich darüber Gedanken machen, verwenden Sie einfach - =, um sich vom Ereignis zu lösen. Das entfernt die Referenz, die von der Anlage erstellt wird, und vermeidet diese Art von Speicherproblem.

Edit: Da die Kommentare ein wenig lang werden, werde ich hier einige Follow-ups veröffentlichen. Wenn Sie ein Ereignis anhängen, hängen Sie einen Verweis auf sich selbst beim Ereignisanbieter auf. Wenn Sie beispielsweise eine Clock-Klasse mit einem StrikesMidnight-Ereignis haben und dieses Ereignis von einer Klasse namens Bedtime abonnieren, lautet die eigentliche Funktionsweise von Bedtime, dass clock.StrikesMidnight += this.HandleMidnight; lautet, dass Sie clock einen Verweis auf sich selbst zuweisen. Es ist, als hätte Clock eine Objekteigenschaft und du sagtest clock.ObjectProperty = this;

Also, in einem Fall, in dem die Bedtime-Klasse kurzlebig ist und ihren Gültigkeitsbereich verlässt, taucht Bedtime auf, hängt sich einen Verweis auf sich selbst auf Clock und geht dann außer Reichweite. Problem ist, Clock hat immer noch einen Verweis darauf, also, obwohl es außerhalb des Geltungsbereichs ist, sammelt Garbage Collector keine Schlafenszeit.

....

Das ist der Hintergrund. In Ihrem Fall erstellen Sie ein Label und fügen einen Verweis auf sich selbst hinzu (über Ihre "MethodX" -Handler). Wenn die Aktualisierung aufgerufen wird, löschen Sie die Liste der Beschriftungen (dh sie gehen aus dem Gültigkeitsbereich aus). Sie gehen aus dem Rahmen und sie haben Verweise auf Ihre Klasse über ihre MethodX-Handler, aber na und? Sie haben Referenzen nicht verhindert, dass sie GC'ed werden. Niemand hält Referenzen auf sie in Ihrem Code, so dass der GC seine Arbeit an ihnen tun wird und Sie nicht Speicher verlieren.

    
Erik Dietrich 09.04.2012, 18:06
quelle
0

Alle Steuerelemente sollten vom Garbage Collector bereinigt werden, solange Sie das enthaltene Formular entsorgen.

Das Abonnieren des Ereignisses auf den Steuerelementen wird das Steuerelement nicht am Leben erhalten, da das Steuerelement einen Verweis auf den Abwicklungsdelegaten hat; Der Delegat hat keinen Verweis auf das Steuerelement.

Die Situation, in der eine Ereignissubskription verhindert, dass ein Steuerelement bereinigt wird, ist, wenn ein Code im Steuerelement ein Ereignis außerhalb der Formularinstanz abonniert, in der er enthalten ist. Beispiel: Wenn eine benutzerdefinierte Kombinationsbox abonniert wird zu einem Ereignis in einer statischen Klasse, um das Steuerelement zu informieren, wenn seine Optionsliste aktualisiert werden soll. Wenn das benutzerdefinierte Steuerelement dieses Ereignis nicht deaktiviert, wird es von dem Ereignisregister für statische Klassen für die Dauer der Anwendung referenziert. Da das Steuerelement einen Verweis auf seinen Container (usw.) haben wird, wird das gesamte Formular wahrscheinlich im Speicher verbleiben. In solchen Fällen sollte das Steuerelement das Ereignis in seiner Dispose-Methode deaktivieren. Das Abonnieren von Ereignissen in statischen Klassen oder langlebigen Instanzklassen sollte immer eine rote Markierung auslösen und explizit deaktiviert werden, wenn sie nicht mehr benötigt werden.

Solange in Formularen alle Ereignisse mit Instanzmethoden in der Formularklasse oder mit Objekten verknüpft sind, deren Bereich von der Formularinstanz gesteuert wird, werden die Steuerelemente bereinigt, wenn das Objektdiagramm das Formular rootet geht aus dem Rahmen. Seien Sie jedoch vorsichtig, dass externe Klassen keinen Verweis auf das Formular enthalten, nachdem es nicht mehr benötigt wird.

    
Preston McCormick 09.04.2012 19:02
quelle
0

Mein erster Vorschlag wäre, nicht vorzuspannen. Stellen Sie sicher, dass dies ein Problem ist, bevor Sie versuchen, es zu lösen.

In Bezug auf Dispose (): Dispose sollte ONLY verwendet werden, um nicht verwaltete Ressourcen freizugeben, bevor ein Objekt als Garbage Collection erfasst wird. Weitere Informationen finden Sie Ссылка .

Damit Ereignishandler keine Verweise auf Ihre Steuerelemente behalten, müssen sich Ihre Steuerelemente von allen Ereignishandlern abmelden, die sie bei ihrer Erstellung abonniert haben. HINWEIS: Wenn Sie Ereignishandler über die GUI hinzufügen, untersuchen Sie den automatisch generierten Code, um vor dem Aufruf von FlowLayoutPanel.Controls.Clear() zu sehen, von was Sie sich abmelden müssen. Ein clean (-er?) Weg dies zu tun wäre, ein eigenes Steuerelement zu erstellen, das vom gewünschten Steuerelement erbt und eine 'Cleanup ()' Methode hinzufügt, die sich von jedem Ereignis-Handler abmeldet, der abonniert wurde (Sie sollten wissen welches Ereignis) Handler wurden abonniert - entweder, weil Sie den Code geschrieben haben oder er für Sie generiert wurde.

    
Dan Busha 09.04.2012 20:06
quelle

Tags und Links