WPF Memory Leak mit ListView

  • WPF

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    WPF Memory Leak mit ListView

    Hallo,

    in meinem Twitch Viewer Display ich habe eine ListView für den Chat. Das ListViewItem ist ein UserControl (ChatRow.xaml.cs (Github)). Eine ObservableCollection mit dem Datenmodell für das UserControl ist an die ListView gebunden. So weit schön und gut.

    Wenn sich die Liste füllt, werden innerhalb jedes ChatRow-Controls dynamisch weitere UIElemente erzeugt - TextBlocks für den Text, Images für die Emoticons. Auch wenn ich weiß, dass UIElemente im Codebehind erstellen nicht guter WPF-Stil ist, wüsste ich nicht wie ich das anders machen soll. Ist prinzipiell aber egal, performancetechnisch läuft das ganze 1A - da bin ich echt beeindruckt, was die Hardwarebeschleunigung da bringt.

    Leider zieht das aber auch nicht unwesentlich Arbeitsspeicher. Meine Idee war es, die ObservableCollection von Zeit zu Zeit zu Clearen, um wieder Speicher freizugeben. Allerdings wird zwar die ObservableCollection gecleared und in der ListView ist dann auch gähnende Leere - jedoch verbleiben offensichtlich alle ChatRow-Controls im Arbeitsspeicher, auch wenn sie nicht mehr angezeigt werden und werden vom GC auch nicht gelöscht. Ja, ich habe testweise das IDisposable-Pattern implementiert und darin auch alle Children des Stackpanels im ChatRow-Control entfernt (Dispose implementieren diese ja nicht) und nein, leider verbleiben die ChatRows im Arbeitsspeicher.

    Meine Frage nun: Was referenziert noch auf die ChatRow-Objekte, dass diese vom GC nicht einkassiert werden? Die ChatRows werden ja vom Framwork erstellt. Könnte dieser Teil im ChatRow-Control etwas ausmachen:

    C#-Quellcode

    1. DependencyPropertyDescriptor tagsDesc = DependencyPropertyDescriptor.FromProperty(TagsProperty, typeof(ChatRow));
    2. tagsDesc.AddValueChanged(this, new EventHandler((object sender, EventArgs e) => updateData()));
    Twitch Viewer Display Chat-, Zuschauer- und Statistiktool für Streamer
    Du bist ja lustig: schreibst eine Wpf-Anwendung, ohne dabei/zuvor die Wpf-Konzepte zu erlernen - dabei kann nur komisches schrulliges Zeug herauskommen.
    Und nu haste iwie ein Memory-Leak eingebastelt, und wir sollen jetzt wissen wo?

    Meine Empfehlung: Erlerne den MVVM-Pattern, bastel ein vernünftiges Viewmodel, verwende Databinding, Styles und Templates.
    (Und wenns dann immer noch so viel Speicher frisst, dann ist das bei Wpf eben so)
    Ein UserControl ist - nach dem, was du bislang berichtest - hier fehl am Platz.
    Ergänzend zur Empfehlung von @ErfinderDesRades folgende Hintergrundinfo: Ob der GC die Objekte einkassiert oder nicht kannst du erst dann beurteilen, wenn der Speicher knapp wird, z.B. weil eine andere Anwendung viel Speicher anfordert. Vorher ist es möglich, dass der GC grade einfach nur faul ist. Alternativ kannst du den Profiler ("Leistungsmessung") laufen lassen - der zeigt dir unter anderem an, wo viel Speicher verbraucht wird. Vor allem gilt aber: Die Lernkurve von WPF ist ziemlich steil - ohne Buch kommt da nur Mist raus, und die ersten 10 WPF-Programme gehören fast immer in die Tonne.
    Gruß
    hal2000
    Ich habe mich jetzt die letzten Tage durch einige Artikel über MVVM und WPF gelesen... bevor ich jetzt mein ganzes Projekt auf MVVM umkrempel, will ich sichergehen dass ich das auch richtig verstanden habe.
    Deshalb habe ich hier ein kleines Schema entwickelt (unabhängig von der Frage im OP, wollte aber dafür jetzt nicht noch einen neuen Thread aufmachen):


    Zuerst zum oberen Teil des Bildes: so hatte ich das bisher implementiert, das sollte ja aber MVVM entsprechen, richtig?

    Bei dem unteren Teil bin ich ziemlich verwirrt: Bei heise wird das Model als die Logik-beinhaltende Schicht dargestellt, bei Codeproject dagegen (so wie ich das auch vom MVC-Pattern her kenne) ist das Model nur als daten-beinhaltendes Element dargestellt:
    Business logic is typically kept separate from the model, and encapsulated in other classes that act on the model.


    Im Thread Wpf und MVVM - Verständnisfrage schreibt EDR:

    ErfinderDesRades schrieb:

    Daten-Zugreiferei eine Geschichte von Static Classes

    -> In meinem Schema sollte also der IRC-Client eine statische Klasse sein (bisher hatte ich ihn, wie in der Abbildung dargestellt, im ViewModel instanziiert), deren Events vom ViewModel? (eigentlich ja nicht, aber wo sonst?) abbonniert werden. Wenn das Event invoked wird, kann ich im ViewModel den entsprechenden ChatEntry zur ObservableCollection hinzufügen.

    Ist das soweit alles MVVM konform oder habe ich das Pattern komplett missverstanden?
    Twitch Viewer Display Chat-, Zuschauer- und Statistiktool für Streamer
    Ja, das ist die lausige "Was ist eiglich das Model?" - Diskussion - da gibts keine Einigkeit. (Also wenn du das "richtig" machen willst im Sinne von "jedem recht", dann machste dich verrückt.)

    Einig ist man sich nur in dem Punkt, dass das View (möglichst aussschließlich) über Bindings mit dem Viewmodel kommuniziert.
    Und das ist auch der wichtigste Punkt, und Ausgangspunkt, und mit weiterem würde ich weitermachen, wie's sich als praktisch ergibt.

    Zu deine Bildle: Jo, manche nennen ihr Mainmodel auch MainWindowViewmodel (damits ein längeres Wort ist, dann sieht der Code wichtiger aus ;) ).
    Bei mir heissts aber bewusst "MainModel", und ist die codeseitige "Zentrale" meiner Anwendungen, und nicht immer ist direkt ein MainWindow auch daran gebunden.
    Guck mal im Wpf-Tutorial-Bereich des Forums, da fährt einiges rum, was für dich höchst interessant sein könnte, zu dieser Frage jetzt etwa unbedingt Grundlagen - MVVM-Anwendungs-Struktur angugge.
    Und auch ganz wichtig: Grundlagen - MVVM: "Binding-Picking" im Xaml-Editor dass du ühaupt mal siehst, wie der Xaml-Editor arbeiten kann, wenn man die DataContexte in geeigneter Weise festlegt.

    Eiglich hab ich im ersten Link nu alles gesagt, aber ich fasse nochmal zusammen:
    • Bei mir ist das MainViewmodel die "CodeZentrale", die hat viele Properties, die jeweils UnterVMs bereitstellen.
    • MainViewmodel ist ein public Singleton
    • Jedes Window, oder auch UserControl kann daher seinen DataContext durch den MainViewmodel-Baum hindurch auf (fast) jedes Viewmodel setzen
    • Das ist sehr fein, denn so kann ich auch Test-Daten generieren, und habe im XamlEditor dadurch noch besseres Wysiwyg
    • Daten Laden - oder in deim Fall mit dem IRC rummachen - ist (fast immer) Aufgabe des MainViewmodels - also nicht in dem Sinne, dass das da im Einzelnen gecodet ist, sondern das MainViewmodel hat Zugriff auf die Datenbeschaffung, und das kann (über Bindings) natürlich auch vom User ausgelöst wern.
      Nenne es "Das MainViewmodel hat Zugriff auf die Daten-Schicht", und die Architektur-Astronauten sinds zufrieden (einige jedenfalls) :P
    Hier kannst du dich auch noch dumm und dämlich lesen zum Thema:
    mycsharp.de/wbb2/thread.php?postid=3787718#post3787718
    Besonders schätze ich dort Latinos Einlassungen, nur musste bedenken, der arbeitet iwie in sehr großen Projekten mit, und von daher hat er eine gewisse Neigung, Dinge doch noch bischen komplizierter zu machen als für unseren Kleinkram wirklich nötig.

    Wo ich drüber nachdenke: Vlt. sollte ich mein MainViewmodel anders nennen - "ApplicationModel" wäre evtl. treffender, denn es modelliert mehr als nur die Oberfläche.
    Kinners - ich hab den neuen Wpf-Pattern erfunden: AMVVM 8o

    Nochmal konkret zur Frage

    newcat schrieb:

    Ist das soweit alles MVVM konform (oberes Bildle)?
    Jo, ist ok, sogar Latino wird da zustimmen, wenn er meinen Begriff von "Model" zugrundelegt - er hat eiglich nämlich einen anderen.

    Mir ist die Hauptsache, dass du den Codebehind leer lässt, und insbesondere dort den DataContext nicht setzst, sondern im Xaml - damit du gescheites Wysiwyg hast.
    Wennde das erfolgreich bewältigst, dann kanns nicht mehr so falsch sein, was du verzapfst.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()