myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Basistechnologien und allgemeine .NET-Klassen » Wie gebe ich den Speicher bei Arrays oder Listen wieder frei?
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Wie gebe ich den Speicher bei Arrays oder Listen wieder frei?

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
BerndFfm BerndFfm ist männlich
myCSharp.de-Team

avatar-3299.jpg


Dabei seit: 20.01.2006
Beiträge: 3.622
Entwicklungsumgebung: Visual Studio 2015
Herkunft: Frankfurt a.M.


BerndFfm ist offline

Wie gebe ich den Speicher bei Arrays oder Listen wieder frei?

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

ich bin jetzt auf einen Fehler in meinen Applikationen gestoßen nachdem 2 Kunden öfter einen Memory Overflow hatten. Alle Protokolle haben nichts ausgesagt.

Jetzt habe ich festgestellt dass es durch Arrays / Lists kommt deren Speicher nicht freigegeben wird.

Hintergrund : Vor langer Zeit habe ich nach einer Möglichkeit gesucht um Bildschirmlisten mit großen Datenmengen sehr schnell anzuzeigen. Etwas Fertiges gab es damals nicht, deshalb habe ich das wie folgt selber gebaut :

Virtuelles ListView, es werden die ersten 30 Zeilen angezeigt, dann wird "Fertig" vorgegaukelt. In einem eigenen Thread wird im Hintergrund ein Array mit den Items gefüllt. Die Zeilen werden nur hergestellt wenn man tatsächlich hinblättert (Lazy Loading).
So wird eine Liste mit über eine Millionen Datensätzen in einer Sekunde angezeigt.
Nur wenn man nach einer Spalte sortiert dauert es länger.

Die ListViewItems speichere ich in einem Array, das ist der Klasse als private definiert ist.

C#-Code:
private ListViewItem[] adr;

private void InitList()
{
    adr = new ListViewItem[anzzeilen];
    Thread t = new Thread(ArrayFuellen);
    t.Start();
}

Auch nach Beenden der Klasse und Dispose bleibt der Speicher durch das Array belegt. Auch wenn der Thread beendet wird.

Auch ein Umbau auf List<> ergibt keine Änderung.

Alle Bordmittel von .NET schlagen fehl, der Speicher bleibt auf jeden Fall belegt.

Übrigens : Ist .NET 3.5.

Welche Möglichkeiten gibt es den Speichern freizugeben ?

Oder mehrere ListViewItems so zu speichern dass der Speicher wieder freigegeben wird ?

Grüße Bernd
23.10.2020 11:00 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.805
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ich denke, das liegt nicht am Array, sondern an den einzelnen ListViewItems. Sind diese noch der  ListView zugeordnet (oder anderweitig als Referenz)?

Ansonsten könntest du auch ja mal den Memory-Profiler laufen lassen und schauen, welche Objekte nach vermeintlicher Freigabe noch existieren.
23.10.2020 11:12 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Palladin007 Palladin007 ist männlich
myCSharp.de-Mitglied

avatar-4140.png


Dabei seit: 03.02.2012
Beiträge: 1.363
Entwicklungsumgebung: Visual Studio 2019
Herkunft: NRW


Palladin007 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Wenn es noch irgendwo eine Referenz auf dieses Array gibt, wird der Speicher nie freigegeben.

Also suche, wo es noch Referenzen gibt und sorge dafür, dass die nicht erhalten bleiben, wenn aufgeräumt werden soll.
Events sind da ein beliebter Fehler, denn die sorgen zwangsläufig dazu, dass deine Instanz (die wiederum das Array hat) bei der Instanz, die das Event pflegt, referenziert bleibt.

Zitat:
Auch nach Beenden der Klasse und Dispose bleibt der Speicher durch das Array belegt

Eine Klasse kann nicht "beendet" werden. Solange noch Referenzen existieren, räumt der GC nicht auf, völlig egal, was Du in deinem Dispose (was ja auch nur eine dumme Methode ist) tust.
Du könntest im Dispose die Variable mit dem Array auf null setzen, das funktioniert aber nur, wenn es keine weiteren Referenzen gibt. Außerdem ist das vermutlich noch nicht das eigentliche Problem, denn irgendetwas hält eine Referenz auf das Objekt, wo das Array drin ist und diese Stelle musst Du finden.

Zitat:
Welche Möglichkeiten gibt es den Speichern freizugeben ?

Alle Referenzen entfernen, danach räumt der GC von alleine auf.
Wenn der GC nicht aufräumt, gibt's noch Referenzen.


PS:
Und Th69 hat natürlich Recht: Es kann alles noch an der ListView hängen, dann hast Du damit auch eine Referenz, die Du aufräumen musst.
Da sollte es aber reichen, die Liste mit den ListItems zu leeren und/oder die DataSource auf null zu setzen.

Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von Palladin007 am 23.10.2020 11:18.

23.10.2020 11:16 Beiträge des Benutzers | zu Buddylist hinzufügen
BerndFfm BerndFfm ist männlich
myCSharp.de-Team

avatar-3299.jpg


Dabei seit: 20.01.2006
Beiträge: 3.622
Entwicklungsumgebung: Visual Studio 2015
Herkunft: Frankfurt a.M.

Themenstarter Thema begonnen von BerndFfm

BerndFfm ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Meiner Meinung nach sind alle Referenzen entfernt.

Aber das ist ein guter Hinweis, werde ich mal genau untersuchen.

Grüße Bernd
23.10.2020 12:24 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
gfoidl gfoidl ist männlich
myCSharp.de-Team

avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.674
Entwicklungsumgebung: VS 2019
Herkunft: Waidring


gfoidl ist online

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo BerndFfm,

die Ursache / Lösung der anderen ist die sauberste Art und Weise das zu handhaben.
Tipp: VS Performance Profiler -> .NET Object Allocation Tracking, dort kannst du die "Wurzeln" betrachten.

Sonst ev. auch  Weak References.

mfG Gü
24.10.2020 11:00 Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.805
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

@BerndFfm: Bist du jetzt weitergekommen?
27.10.2020 08:47 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
BerndFfm BerndFfm ist männlich
myCSharp.de-Team

avatar-3299.jpg


Dabei seit: 20.01.2006
Beiträge: 3.622
Entwicklungsumgebung: Visual Studio 2015
Herkunft: Frankfurt a.M.

Themenstarter Thema begonnen von BerndFfm

BerndFfm ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Nein, noch nicht.

Habe erstmal Quick and Dirty eine Meldung ins Programm eingebaut dass man das Programm neu starten soll wenn mehr als 1000 MB belegt sind.

Ich werde berichten.

Grüße Bernd
27.10.2020 09:15 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Spook Spook ist männlich
myCSharp.de-Mitglied

Dabei seit: 28.10.2008
Beiträge: 221
Entwicklungsumgebung: VS2019
Herkunft: Esslingen a.N.


Spook ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo BerndFfm,

handelt es sich um WPF oder um Forms?

Grüße
27.10.2020 09:25 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
BerndFfm BerndFfm ist männlich
myCSharp.de-Team

avatar-3299.jpg


Dabei seit: 20.01.2006
Beiträge: 3.622
Entwicklungsumgebung: Visual Studio 2015
Herkunft: Frankfurt a.M.

Themenstarter Thema begonnen von BerndFfm

BerndFfm ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Die Anzeige erfolgt mit einem ListView im VirtualMode.

Das ist WinForms.

Grüße Bernd
27.10.2020 11:53 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.565
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Bist Du weitergekommen ?

Was wird in ArrayFuellen() gemacht ? Ein Event abonniert ?

Grüße MrSparkle
27.10.2020 15:36 Beiträge des Benutzers | zu Buddylist hinzufügen
BerndFfm BerndFfm ist männlich
myCSharp.de-Team

avatar-3299.jpg


Dabei seit: 20.01.2006
Beiträge: 3.622
Entwicklungsumgebung: Visual Studio 2015
Herkunft: Frankfurt a.M.

Themenstarter Thema begonnen von BerndFfm

BerndFfm ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

In ArrayFuellen wird nichts besonderes gemacht, auch keine Events abonniert.

Ich muss das mal genau analysieren wenn ich mehr Zeit habe.

Ich werde berichten.

Grüße Bernd

C#-Code:
...
    Liste.VirtualMode = true;
    Liste.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(Liste_RetrieveVirtualItem);
    Liste.VirtualListSize = anzzeilen;
...

private ArrayFuellen()
{
    int m = 0;
    foreach(row ...)
    {
        ListViewItem lvItem = new ListViewItem(inhalt);
        for (int i = 1; i < anzspal; i++)
        {
            lvItem.SubItems.Add(...);
        }
        adr[m] = lvItem;
        m++;
    }
}

private void Liste_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    if (adr[e.ItemIndex] != null)
        e.Item = adr[e.ItemIndex];
    else
    {
        e.Item = new ListViewItem("");
        for (int i = 1; i < anzspal; i++) e.Item.SubItems.Add("");
    }
}
28.10.2020 15:17 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Th69
myCSharp.de-Poweruser/ Experte

avatar-2578.jpg


Dabei seit: 01.04.2008
Beiträge: 3.805
Entwicklungsumgebung: Visual Studio 2015/17


Th69 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zweite Nachfrage, da es mich sehr interessiert - gibt es Updates deinerseits?
13.11.2020 15:36 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
jogibear9988 jogibear9988 ist männlich
myCSharp.de-Mitglied

Dabei seit: 17.07.2007
Beiträge: 565
Entwicklungsumgebung: VS 2010 RC
Herkunft: Offenau


jogibear9988 ist offline

Virtualisierung...

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Noch als Info, für die Virtualiserung (hatte das früher auch mal in WPF gebraucht), hatte ich damals das eingesetzt  https://github.com/dotnetprojects/VirtualCollection (stammt nicht von mir, hab es nur geforkt und ein paar dinge gefixt)
18.11.2020 22:40 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als ein Monat.
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 30.11.2020 11:32