Lutz-IT GmbH - Ihr Partner für IT-Consulting und Programmierung
  • Email
  • Rss
Tel: +41 76 459 0580
  • IT-Consulting
  • Programmierung
  • Showcases
  • Blog
  • Referenzen
  • Auszeichnungen
  • Kontakt
Search the site...
Home» Programmierung » Memory leaks bei eventbasierten Architekturen

Memory leaks bei eventbasierten Architekturen

Posted by Benjamin Lutz - 6. Mai 2011 - Programmierung
0

Die Problematik von Memoryleaks durch Eventhandler wurde mir in den vergangenen Tagen wieder deutlich vor Augen geführt.

Ausgangssituation:
Ein Silverlight 4 Client, welcher das MVVM (Model View ViewModel) implementiert, benötigt im ViewModel die Benachrichtigung wenn sich in einer ObservableCollection des Models etwas verändert hat (Add, Remove). Die einfachste Möglichkeit ist, sich am CollectionChanged Event zu abonieren.

Das funktioniert alles prima. Doch nun navigiert der Benutzer wo anders hin und die View sowie das ViewModel müssen freigegeben werden. Werden Sie aber nicht! Warum? Ganz einfach. Die View hat durch die Bindings Referenzen auf das ViewModel. Das Model ist dem Ganzen übergeordnet und muss überleben. Das Problem ist, dass das Model durch die Event Registrierung eine Referenz auf das ViewModel in Form eines Callbacks hält.

Aus diesem Grund wird View und ViewModel erst mit der Freigabe des Models freigegeben. Navigiert der Benutzer nun einige Male hin und her dann wird dieser Effekt mit Sicherheit in einer OutOfMemoryException enden, da die Views meist recht speicherintensiv sind.

Weisen wir nun als Erstes den Sachverhalt mit einer Konsolenapplikation nach:

    static void Main()
    {
        var model = new TestModel();
        var viewModel = new TestViewModel();
        model.TestEvent += viewModel.ViewModelEventHandler;
        model.RaiseEvent();
        viewModel = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        model.RaiseEvent();
        model.RaiseEvent();
    }

    public class TestModel
    {
        public event EventHandler TestEvent;

        public void RaiseEvent()
        {
            if (TestEvent != null) TestEvent(this, EventArgs.Empty);
        }
    }

    public class TestViewModel
    {
        public void ViewModelEventHandler(object sender, EventArgs e)
        {
            Console.WriteLine("Event fired!");
        }
    }

Auf der Konsole wird 3x “Event fired!” stehen, da das ViewModel trotz Freigabe der Instanz und explizitem Aufruf des Garbage Collectors nicht freigegeben wird. Es versteht sich von selbst, dass die Aufrufe der GC Klasse hier nur zu Anschauungszwecken dienen und nicht in produktivem Code verwendet werden.

Das Problem lässt sich recht einfach mit diesem Code Snippet lösen.

    public class WeakEventHandler where TEventArgs : EventArgs
    {
        public WeakEventHandler(object eventSource, string eventName, object eventDestination, string eventHandlerName)
        {
            var weakSourceReference = new WeakReference(eventSource);
            var weakDestiantionReference = new WeakReference(eventDestination);
            EventHandler = delegate(object sender, TEventArgs e)
            {
                if (weakDestiantionReference.IsAlive)
                {
                    //Invoke EventHandler if object is still alive.
                    weakDestiantionReference.Target.GetType().GetMethod(eventHandlerName).Invoke(weakDestiantionReference.Target, new[] { sender, e });
                }
                else if(weakSourceReference.IsAlive)
                {
                    //Deregister the Event because source is not alive anymore.
                    weakSourceReference.Target.GetType().GetEvent(eventName).GetRemoveMethod().Invoke(weakSourceReference.Target, new[] { EventHandler });
                }
            };
        }

        public EventHandler EventHandler { get; private set;}
    }

Die Registrierung des Events sieht dann wie folgt aus:

model.TestEvent += new WeakEventHandler(model, "TestEvent", viewModel, "ViewModelEventHandler").EventHandler;

Der Unterschied besteht darin, dass ein Eventhandler dieser Wrapper Klasse registriert wird. Der Verweis auf das eigentliche Objekt wird über eine WeakReference gehalten. Die Klasse fungiert dabei als Router und checkt beim Aufrufen des EventHandlers, ob das eigenliche Zielobjekt – in diesem Fall das ViewModel – noch lebt. Wurde das ViewModel bereits freigegeben, wird der eigene Eventhandler deregistriert und auch diese Klasse wird freigegeben. Es gibt jedoch 2 Haken an dieser Lösung:

1. Solange das Event nicht nach der Freigabe des ViewModels ausgelöst wird, wird die Wrapper Klasse nicht freigegeben. View und ViewModel tangiert dies nicht. Da die Klasse sehr schmal ist, wird man damit leben können.

2. Die Eventregistrierung ist nicht typisiert. Sowohl der Eventname als auch der Handlername werden als Strings mitgegeben. Ich persönlich finde das zwar hässlich, habe aber keine andere Möglichkeit gefunden, da man zwar den Handlernamen über eine LinqExpression typisiert übergeben kann aber bei dem Event gelingt dies nicht.

Fazit:
Die aufgezeigte Lösung schafft Abhilfe für das Problem, hat aber auch ihre Tücken. Am Saubersten ist die EventHandler, sobald man die Instanz nicht mehr benötigt, manuell abzuhängen. Allerdings erfordert dies eine Menge Disziplin und man muss auf anonyme Methoden verzichten.

Events, Memory Leaks, Silverlight
0 comments
  Livefyre
  • Get Livefyre
  • FAQ
Sign in
+ Follow
Post comment
 
Link
Newest | Oldest

Neueste Artikel

  • Windows Service Installation Simplified

    17. Juni 2013
  • Generieren eines Software Architektur Dokuments mit Enterprise Architect

    21. Mai 2013
  • .NET 4.5 Trading API für Interactive Brokers

    6. Mai 2013
  • Windows 8.1 jetzt doch wieder mit Start Menü?

    29. April 2013
  • WCF Service Discovery mit .NET 4

    12. April 2013

    Artikel Archiv

    • [+] 2013 (15)
      • [+] Juni (1)
        • Windows Service Installation Simplified
      • [+] Mai (2)
        • Generieren eines Software Architektur Dokuments mit Enterprise Architect
        • .NET 4.5 Trading API für Interactive Brokers
      • [+] April (3)
        • Windows 8.1 jetzt doch wieder mit Start Menü?
        • WCF Service Discovery mit .NET 4
        • Hackerangriff auf Blog durch SQL-Injection
      • [+] März (3)
        • Distributed Event Aggregator bzw. ServiceBus simplified
        • Aspekt orientierte Programmierung (AOP)
        • Testautomatisierung mit Unittests und Moq
      • [+] Februar (2)
        • Unleash the power of Domain-Specific Language in VS2012
        • Benutzeroberflächen ergonomisch gestalten
      • [+] Januar (4)
        • Trend Trading System App für Windows 8 verfügbar
        • Erfahrungsbericht: Domain Oriented N-Layered von Microsoft Spain
        • Kommunikationsszenarien mit NServiceBus 3.3
        • HTML5 Anwendung als WinRT Application veröffentlichen
    • [+] 2012 (28)
      • [+] Dezember (1)
        • DataBinding und das MVVM-Pattern in HTML5
      • [+] November (2)
        • Der Unterschied zwischen Sieger- und Verlierertypen
        • Tücken bei der Personalbeschaffung von .NET Entwicklern
      • [+] Oktober (2)
        • Kostenloser Kursdaten REST-Service
        • Migration von .NET 4 Projekten nach WinRT (JS)
      • [+] September (2)
        • Migration von .NET 4 Projekten nach WinRT (XAML)
        • Windows 8 im Praxistest
      • [+] August (1)
        • Eigene Sections in der .NET Standard Konfiguration
      • [+] Juli (2)
        • Steigerung des Marktwerts durch Weiterbildung
        • Effiziente Kostenstrukturen im IT-Consulting - Teil 4
      • [+] Juni (1)
        • Effiziente Kostenstrukturen im IT-Consulting - Teil 3
      • [+] Mai (3)
        • Effiziente Kostenstrukturen im IT-Consulting - Teil 2
        • Effiziente Kostenstrukturen im IT-Consulting - Teil 1
        • Vision eines Entwicklerarbeitsplatzes in der Zukunft
      • [+] April (3)
        • Windows 8 und die Zukunft von Silverlight und WinRT
        • Elegante und Effiziente Data Access Layer mit Dapper.NET
        • Quartalsergebnis Q1/2012 des Trendfolge-Handelssystems
      • [+] März (3)
        • Konfiguration von WCF Services in Silverlight
        • Rapid GUI Prototyping mit Mockups
        • Chancen und Risiken des Entity Frameworks
      • [+] Februar (3)
        • Vorsicht vor Recruiter aus Grossbritannien
        • Financial Chart für Silverlight und WPF
        • Erste Handelssignale 2012
      • [+] Januar (5)
        • Microsoft Silverlight 5 endlich verfügbar
        • Riskmanagement in IT-Projekten
        • Artikelempfehlung: "Schluss mit dem Burnout-Gejammer!"
        • Ursachen von hoher Fluktuation in IT-Projekten
        • Einsatzgebiete von Silverlight5 und HTML5
    • [+] 2011 (36)
      • [+] Dezember (4)
        • Business Objekt Modelle in Entwicklungsprojekten
        • Einsatz von Open Source in Entwicklungsprojekten
        • Buchempfehlung: "Ich weiss, wie du tickst" ISBN 3280054109
        • Prozessverbesserungen für qualitativ hochwertigen Code
      • [+] November (2)
        • Deklarative .NET Programmierung mit Attributen
        • Favorisierte Lösung für Silverlight Reporting
      • [+] Oktober (3)
        • Silverlight Reportinglösungen
        • Testautomatisierung mit Silverlight
        • .NET Schlüsseltechnologien der nächsten Jahre
      • [+] September (4)
        • Hauptgründe für das Scheitern von IT-Projekten
        • Auswahl der Titel für das Handelssystem
        • WebClient Sicherheitsrichtlinien in Silverlight
        • Nachhaltiger Erfolg im Consulting Teil 7 - Projektdauer
      • [+] August (4)
        • Nachhaltiger Erfolg im Consulting Teil 6 - Vertragsverhandlungen
        • Nachhaltiger Erfolg im Consulting Teil 5 - Vorstellungsgespräch
        • Nachhaltiger Erfolg im Consulting Teil 4 - Stundensatzverhandlungen
        • Nachhaltiger Erfolg im Consulting Teil 3 - Bewerbungsmanagement
      • [+] Juli (4)
        • Nachhaltiger Erfolg im Consulting Teil 2 – Onlineportale
        • Nachhaltiger Erfolg im Consulting Teil 1 - Das Profil
        • Integration von Windows Forms Controls in WPF
        • Unittesten von WCF-Services mit der ServiceHost Klasse
      • [+] Juni (4)
        • Verteilte Transaktionen in einer Service orientierten Architektur
        • Service orientierte Architektur und Domain Driven Design
        • View und ViewModel mit MEF unter testbarkeits Aspekten verbinden
        • Entfernung ungenutzter Strings in .NET Resource-Files
      • [+] Mai (5)
        • Enterprise Library Silverlight Integration Pack Validation Block Teil II
        • Enterprise Library Silverlight Integration Pack Validation Block Teil I
        • Programmierung von Streaming Services mit WCF und Silverlight
        • Order Statemachine mit Workflow Foundation 4
        • Memory leaks bei eventbasierten Architekturen
      • [+] April (5)
        • Linq Expressions in der Praxis
        • Handelsregeln mit der .NET Rule Engine umsetzen Teil II
        • Handelsregeln mit der .NET Rule Engine umsetzen Teil I
        • Plugin Mechanismus für Trading Systeme
        • Charttechnik mit .NET
      • [+] März (1)
        • Schaffen der Grundlagen für ein eigenes Handelssystem
    © 2013 Lutz-IT GmbH