Endlos Backgroundworker memory problem



  • maro158 schrieb:

    ABstraCT, Du zeigst uns das Skelett und wir sollen die Leber untersuchen?

    Wenn ich mir das so anhöre, könnte ich wetten, dass Du sowohl in DoWork als auch in OnWork direkt auf Instanz-Variablen zugreifst. Stimmt das? Well, in diesem Fall scheppert das Design Deiner Anwendung ganz laut. Und die Idee mit den Sleeps beeinträchtigt die Performanz des ganzen Systems. Verwende Timer. New-e deine Variablen in WorkerThread. Und nach Ablauf einer Arbeitsrunde verwende:

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    

    Der GC macht seine Arbeit ganz gut. Wenn er nur dazu kommen darf. Und was der Task-Manager über den Verbrauch von Speicher sagt, ist nicht immer wörtlich zu nehmen. Woher weißt Du überhaupt, dass dein Programm ein Speicher-Problem hat? Wirft die Anwendung einen Ausnahmefehler (MemoryOutofRangeException, OutOfMemoryException usw.)? Verwendest Du System-Ressourcen (Handles etc.)? Wenn es einen Crash gibt, was steht dann im System-Log?

    Fragen über Fragen. Poste wirklichen Code und wirkliche Fehlermeldungen, dann kann Dir vielleicht auch wirklich geholfen werden.

    Es hat sich doch schon gestern geklärt das es kein Speicherproblem sondern ein Stack Overflow war ausgelöst durch eine endlos rekursion.



  • Abgesehen dass das Problem ein StackOverlow war, würde ich den GC nie (sag nie nie) direkt beeinflussen (GC.xxx).
    Gruss Simon



  • Knuddlbaer schrieb:

    Wieso beeinflusst das Sleep das gesamte System ?

    Beim Aufruf von Sleep findet ein Übergang aus dem User- zum Kernel-Mode statt. Das ist teuer.



  • simon.gysi schrieb:

    Abgesehen dass das Problem ein StackOverlow war, würde ich den GC nie (sag nie nie) direkt beeinflussen (GC.xxx).
    Gruss Simon

    Manchmal gibt es keine Alternative dazu. Angenommen du hast einen Timer, der alle x Stunden eine Aktivität auslöst. Anschließend passiert nichts mehr außer Warten auf das Auslösen des Timers. Wann glaubst Du dass der GC wieder einspringt?

    Gruss
    maro158



  • Es hat sich doch schon gestern geklärt das es kein Speicherproblem sondern ein Stack Overflow war ausgelöst durch eine endlos rekursion.

    Ja. Aber Erkenntnis ist der beste Weg zur Besserung (des Codes).
    🙂



  • Wenn es nötig ist.



  • simon.gysi schrieb:

    Wenn es nötig ist.

    Ich mag Deine sybillinische Antwort, Simon.

    Wenn 48 Stunden lang keine weiteren Speicher-Anforderungen gemacht werden, hat der GC einfach keine Möglichkeit aktiviert zu werden. Der Speicher bleibt "wie er immer war, nur einsam und verlassen" (Nena) ...



  • OT: Was bedeutet sybillinisch?
    Edit: Habs gefunden.. http://www.duden-suche.de/suche/trefferliste.php?suche=einfach&treffer_pro_seite=10&modus=title&level=125&senden=suchen&suchbegriff[AND]=sibyllinisch

    1. si|byl|li|nisch <Adj.> (bildungsspr.): geheimnisvoll, rätselhaft: -e Worte.



  • simon.gysi schrieb:

    OT: Was bedeutet sybillinisch?
    Edit: Habs gefunden.. http://www.duden-suche.de/suche/trefferliste.php?suche=einfach&treffer_pro_seite=10&modus=title&level=125&senden=suchen&suchbegriff[AND]=sibyllinisch

    1. si|byl|li|nisch <Adj.> (bildungsspr.): geheimnisvoll, rätselhaft: -e Worte.

    Die Sibyllen waren in der griechischen Antike Wahrsagerinnen, berühmt für ihre doppeldeutigen Antworten, aus denen jeder entnehmen konnte, was er für richtig hielt. Der Trick besteht in der Erstellung einer möglichst großen Projektionsfläche für die Phantasie des Deuters. Ganz einfach ist es, indem man kurze, sehr allgemeine Sätze verwendet.



  • maro158 schrieb:

    Wenn 48 Stunden lang keine weiteren Speicher-Anforderungen gemacht werden, hat der GC einfach keine Möglichkeit aktiviert zu werden. Der Speicher bleibt "wie er immer war, nur einsam und verlassen" (Nena) ...

    Was totaler Unsinn ist weil die GC der .Net-Frameworks nicht durch Speicheranforderungen ausgelöst wird:

    ".NET Framework includes a garbage collector which runs periodically, on a separate thread than the application's thread, that enumerates all the unusable objects and reclaims the memory allocated to them.
    "

    Ausserdem wird in der MSDN ausdrücklich davor gewarnt die GC unnötig aufzurufen:

    "Be sure that the application is not inducing garbage collection too frequently because that can decrease the performance if the garbage collector is unproductively attempting to reclaim objects. "



  • maro158 schrieb:

    simon.gysi schrieb:

    Abgesehen dass das Problem ein StackOverlow war, würde ich den GC nie (sag nie nie) direkt beeinflussen (GC.xxx).
    Gruss Simon

    Manchmal gibt es keine Alternative dazu. Angenommen du hast einen Timer, der alle x Stunden eine Aktivität auslöst. Anschließend passiert nichts mehr außer Warten auf das Auslösen des Timers. Wann glaubst Du dass der GC wieder einspringt?

    Gruss
    maro158

    Dann wenn die Generation 0 voll ist und/oder Ressourcen benötigt werden. Wenn der Thread nichts anderes macht als Idlen hat der GC ausreichend Zeit die Ressourcen aufzuräumen.

    Ich konnte keine genaue Angabe dazu finden, in welchem Thread der GC läuft. Mal heißt es im Userthread, dann wieder in einem eigenen Thread auf prio low. Definiert konnte ich nur herausfinden, das auf MultiCore CPUs im Workstation-Modus ein Hintergrund Thread läuft und Objekte markiert damit der GC beim Aufräumprozess sich die Zeit der Suche ersparen kann. Hast Du hier eventuell eine Information zur Hand ? In den Beschreibungen zu "wie arbeitet der GC" sind zwar sehr viele Informationen (z.B. Fallen des GC anhand eines Timers der auf null gesetzt wird - unterschiede Debug und Release betreffend der Referenzirung etc. Aber nichts im Zusammenhang in welchem Thread er läuft (dafür das er alle Managed threads sperrt wenn er aufräumt.)



  • loks schrieb:

    Was totaler Unsinn ist weil die GC der .Net-Frameworks nicht durch Speicheranforderungen ausgelöst wird

    Schön dass Du dir da so sicher bist.



  • ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.de/dv_fxintro/html/d4850de5-fa63-4936-a250-5678d118acba.htm schrieb:

    Wenn Sie einen neuen Prozess initialisieren, wird diesem durch die Common Language Runtime ein zusammenhängender Adressraum reserviert. Dieser reservierte Adressraum wird als verwalteter Heap bezeichnet

    [...]

    Beim Ausführen einer Garbage Collection wird Speicher freigegeben, den von der Anwendung nicht mehr benötigte Objekte beanspruchen. Durch Überprüfen der Stammelemente der Anwendung wird ermittelt, welche Objekte nicht mehr verwendet werden. Jede Anwendung verfügt über einen Satz von Stammelementen. Jedes Stammelement bezieht sich entweder auf ein Objekt im verwalteten Heap oder ist auf NULL festgelegt. Die Stammelemente einer Anwendung beinhalten globale und statische Objektzeiger, lokale Variablen und Referenzobjektparameter im Stapel des Threads sowie CPU-Register. Der Garbage Collector hat Zugriff auf eine Liste der aktiven Stammelemente, die vom JIT (Just-In-Time)-Compiler und der Common Language Runtime verwaltet wird.

    [...]

    Tatsächlich wird eine Garbage Collection erst dann eingeleitet, wenn der Bereich von Generation 0 voll ist. Versucht eine Anwendung, ein neues Objekt zu erzeugen, und der Bereich der Generation 0 ist voll, wird vom Garbage Collector ermittelt, dass es in diesem Bereich keinen freien Adressraum mehr gibt, der dem neuen Objekt zugewiesen werden kann. Daraufhin wird eine Garbage Collection gestartet, um im Bereich der Generation 0 freien Adressraum zu schaffen. Dabei werden nur die Objekte im Bereich der Generation 0 untersucht und nicht alle Objekte im verwalteten Heap.

    ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.de/dv_fxconfig/html/ba2c6c67-5778-497c-9fac-5f793b5500c7.htm schrieb:

    Eine Garbage Collection kann durch die Common Language Runtime (CLR) gleichzeitig in einem separaten Thread oder im selben Thread wie die Anwendung ausgeführt werden. Standardmäßig wird die Garbage Collection durch die Common Language Runtime gleichzeitig ausgeführt, was aber zu Leistungseinbußen führt. Wenn Ihre Anwendung singlethreaded ist und eine intensive Interaktion mit dem Benutzer impliziert, lassen Sie die gleichzeitige Garbage Collection aktiviert, sodass die Anwendung für die Ausführung der Garbage Collection nicht angehalten werden muss.

    Microsoft Press - Microsoft .Net Framework-Programmierung mit C# ISBN 3860639846 2. Ausgabe Seite 473ff schrieb:

    Wenn ein Prozess initialisiert wird, reserviert die CLR ein zusammenhängendes Stück Adressraum, das anfangs nicht mit mit realem Speicher hinterlegt ist. Diese Region des
    Adressraums ist der verwaltete Heap. Der Heap verwaltet einen Zeiger, den ich mit NextObjPtr bezeichne. Dieser Zeiger weist auf die Adresse innerhalb des Heaps, an der das nächste Objekt angelegt wird. Anfangs zeigt NextObjPtr auf die Basisadresse des reservierten Speichers.

    Der IL Befehl newobj legt ein Objekt an.
    [...]
    Beim Ausführen des Befehls newobj führt die CLR folgende Schritte durch:
    [...]

    3. Die CLR prüft, ob die benötigte Anzahl von Bytes im reservierten Adressraum verfügbar ist (bei Bedarf wird ein Adressbereich im Speicher hinterlegt). Falls genügend Platz auf dem verwalteten Heap frei, passt das Objekt hinein und es wird an der Adresse angelegt, auf die NextObjPtr zeigt.
    [...]

    Wenn eine Anwendung mit new ein Objekt anlegt, ist unter Umständen nicht genug Adressraum übrig, um das Objekt zu erstellen. Der Heap entdeckt den Speichermangel, wenn er die Größe des Objektes zur Adresse in NextObjPtr addiert. Liegt das Ergebnis hinter dem Ende des reservierten Adressbereichs, ist der Heap voll. Eine Gargabe Collection muss druchgeführt werden.

    Microsoft Press - Microsoft .Net Framework-Programmierung mit C# ISBN 3860639846 2. Ausgabe Seite 491 schrieb:

    Es gibt 5 Ereignisse, die dazu führen, das eine Garbage Collection ausgeführt wird.

    • Generation 0 ist voll. [...]
    • Code ruft explizit die statische Methode Collect von System.GC auf [...]
    • Windows meldet, dass der Speicher knapp wird [...]
    • Die CLR schließt eine AppDomain. Wenn eine AppDomain geschlossen wird, betrachtet die CLR keine Objekte der AppDomain mehr als Wurzeln [...]
    • Die CLR wird beendet: Die CLR wird beendet, wenn ein Prozess normal endet.

    [...]
    Die CLR verwendet einen speziellen Thread, der ausschließlich die Aufgabe hat, Finalize Methoden aufzurufen. Wenn eine Finalize Methode bei den ersten vier Ereginissen in die Endlossschleife gerät, wird dieser spezielle Thread blockiert, er kann keine weiteren Finalize Methoden mehr aufrufen. Dies ist eine üble Sitution, weil die Anwendung nicht mehr in der Lage ist, den Speicher von abgeschlossenen Objekten wieder zu verwenden. Die Anwendung verursacht ein Speicherleak, bis sie beendet wird.

    Beim fünften Ereginiss erhält jede Finalize Methode etwa 2 Sekunden. Kehrt eine Finalize-Methode innerhalb dieses Zeitraums nicht zurück, beendet die CLR den Prozess einfach. Aucvh wenn es mehr als 40 Sekunden dauert, die Finalize-Methoden sämtlicher Objekte auszuführen, beendet die CLR einfach den Prozess.

    Code in einer Finalize-Methode kann neue Objekte anlegen. Falls das passiert, während die CLR herunterfährt, wird die CLR weiterhin Objekte beseitigen und ihre Finalize Methoden aufrufen, bis es entweder keine Objekte mehr gibt oder bis die 40 Seknunden abgelaufen sind. [...]

    Microsoft Press - Microsoft .Net Framework-Programmierung mit C# ISBN 3860639846 2. Ausgabe Seite 518ff schrieb:

    Der Garbage Collector der CLR optimiert sich selbst. Das bedeutet, dass er bei jeder Garbage Collection Informationen über das Verhalten der Anwendung gewinnt. Wenn Ihre Anwendung zum Beispiel eine Menge Objekte anlegt und nur kurz benutzt, ist es möglich, dass bei der Garbage Collection für die Generation 0 viel Speicher zurückgewonnen wird. Es kann sogar sein, dass sämtliche Objekte aus der Generation 0 beseitigt werden können. Wenn der Garbage Collector feststellt, dass nach dem Bearbeiten der Generation 0 kaum Objekte übrig geblieben sind, könnte er beschließen, die Größenschwelle für die Generation 0 von 256kByte auf 128KByte zu verringern. Das führ dazu, das öfters eine Garbage Collection druchgeführt wird, aber der Garbage Collector wird weniger Arbeit haben, sodass die Arbeitsseiten Ihres Prozesses klein bleiben. [...]

    Und das ganze in die andere Richtung, wenn Generation kaum ein Gewinn bringt, könnten die Grenzen für die Generation 0 größer werden.

    Darüber hinaus wird auf Seite 530 erläutert, das auf Multicore CPUs ein eigener Thread damit beschäftigt ist, nicht erreichbare Objekte zu markieren.

    Mir fehlt hier aber nun folgendes Wissen:

    Wie wird der Heap des Prozesses vergrößert? Es wird beschrieben, das die Generationen geändert werden. Dies lässt vermuten, das so die Generation 2 wachsen kann und ggf. Generation 1 und 0 durch verschieben ihrer Grenzen dann in den erweiterten Bereich eindringen können. Wie stellt dann aber die CLR sicher, das der Heap nicht Fragmentiert ? Es wird ja damit geworben, das keine Fragmentierung stattfindet und erklärt, das man gegenüber z.B. C nicht in die Situation kommt, in der in der Summe zwar ausreichend Speicher vorhanden ist, aber wegen der Fragmentierung nicht genutzt werden kann.

    Entweder gibt es dieses Problem auch unter der CLR, der Heap selbst ist Fragmentiert oder man hat doch wieder das Problem, das eventuell Speicher vorhanden ist aber nicht genutzt werden kann. Man könnte aber auch annehmen, das die CLR in der Lage ist, die Prozesseigenen Heaps wiederum so zu defragmentieren, das ALLE .Net Prozesse angehalten werden und die Heaps verschoben werden (was mir aber selbst als Vermutung zu wage ist.)

    Da wir ja schon auf dem Status sind, das man sich gegenseitig des Nichtwissens bzw. des besserwissens bezeichnet, kann vllt. jemand etwas dazu sagen. Ich finde die Dokumentation hier unzureichend oder widersprüchlich.

    Wie man oben lesen konnte, wird die Aufräumarbeit durch Speicheranforderung (Generation 0 hat kein Platz) oder Abbruch / Entladen getriggert. Ebenso wird diese getriggert, wenn Windows Speicherknappheit meldet. Speziell hier stellt sich dann aber die Frage, in welchem Thread die Collection abläuft - ist es der Thread der durch das Warten blockiert wird, ist es tatsächlich erforderlich das man bei langen Wartezeiten die Aufrufe per Hand vornimmt. Idlet der Thread aber nur, dürfte dadurch der Speicher aus in den Genuss der Garbage Collection kommen.

    Je nachdem wo der GC läuft bzw. auf welcher Prozessorstruktur bzw. welcher Application.Config erscheint es auch Notwendig zu sein, den Garbage Collector manuell aufzurufen,
    wenn man gegenüber der CPU eine hohe Last erzeugt. Liest man oben doch, das man die CLR zwingen kann, den GC in den Anwendungsthread zu verlagern.

    Auf der anderen Seite ist aus dem Buch zu entnehmen, das der GC selbstlernend ist. Mit jedem manuellen Collect könnte man sich negativ in diesen "Lernprozess" einmischen. Letztendlich wird dies aber ein Profiler auf der Zielplattform untersuchen müssen.

    Die Dokumentation zum GC ist zwar Umfangreich, lässt aber meiner Meinung nach noch Fragen offen und ersetzt die "Memoryleak" Probleme durch eine Palette neuer Probleme.

    Man möge mal folgendes Fragment wie folgt ausführen:

    • als Debug im VS gestartet
    • als Debug direkt gestartet
    • als Release im VS gestartet
    • als Release direkt gestartet
    using System;
    using System.Threading;
    
    public static class Program
    {
        public static void Main()
        {
            Timer t = new Timer(TimerCallBack,null,0,2000);
            Console.ReadLine();
        }
    
        private static void TimerCallBack(object state)
        {
            Console.WriteLine(DateTime.Now);
            GC.Collect(); // Aufräumen erzwingen. Das könnte sonst irgendwann mal passieren , wann immer die CLR dazu lustig ist.
        }
    }
    

    Folgendes funktioniert auf dem vollen Framework ohne Probleme:

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace SmartDeviceProject1
    {
        public partial class Form1 : Form
        {
            test te = null;
            public Form1()
            {
                InitializeComponent();
                te = new test();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                te.Main();
            }
        }
    
        public class test
        {
            Graphics gr = null;
            public void Main()
            {
                if (gr == null)
                    gr = Graphics.FromImage(new Bitmap(1, 1));
                gr.MeasureString("Hallo Welt", new Font("Arial", 12,FontStyle.Regular));
                GC.Collect(); // Aufräumen erzwingen. Das könnte sonst irgendwann mal passieren , wann immer die CLR dazu lustig ist.
                GC.WaitForPendingFinalizers();
                GC.Collect(); // Aufräumen erzwingen. Das könnte sonst irgendwann mal passieren , wann immer die CLR dazu lustig ist.
                GC.WaitForPendingFinalizers();
                GC.Collect(); // Aufräumen erzwingen. Das könnte sonst irgendwann mal passieren , wann immer die CLR dazu lustig ist.
            }
        }
    }
    

    Auf einem Windows CE Gerät (CF 2.0 z.B. der PocketPC 2003 Emulator) wird gr zerstört was zu einer Object Disposed Exception führt. (Dies war bereits einmal Bestandteil meinerseits bei einer Diskussion in diesem Forum betreffend des GC.) Eigentlich sollte durch den Verweis auf te festgestellt werden können, das in der Instanz von te gr durch this referenziert wird.

    Welches Verhalten nun das richtige ist, kann ich aus der Dokumentation nicht heraus lesen. Auf jedenfall zeigt es, das man nicht pauschalisieren darf. (Nicht mal im kompletten Framework. Unterschiede bei Singlecore und MultiCore CPU z.B.)

    Man findet jedoch ein paar Hinweise zum GC auf dem CF

    http://chockenberry.blogspot.com/2005/04/net-compact-framework-garbage.html schrieb:

    1. Its not necessarily your application that might cause problem. Since the GC needs to stop all open CF apps on the device, it is very feasible that another application not made by you or under your control could bring about pain. The GC stops all threads and then runs on the thread that called it, but it cleans up ALL threads.

    http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry schrieb:

    3.13.3 GC Heap on CF

    3.13.3.1 Code Pitching
    Besides the GC Heap, the JIT Heap is also in a limited 32 MB address space, so unlike the full CLR, in CF the JITed native code can at times be removed to free memory. This is called Code Pitching.

    3.13.3.2 Single GC Heap
    * There are no generations, no LOH, just a single heap.
    * This is mostly swept, sometimes compacted

    3.13.3.3 Allocations
    Allocations on the GC heap take place in segments
    * Typical segment size = 64k
    * But if you ask for more than 64k memory, segment allocated would be > 64k

    3.13.3.4 Regular Collections
    * Trigger: 1 MB of objects have been allocated since last collection
    * Returning memory to OS:

    1. After each collection, Collector keeps 1 MB of 64k segments
    2. All empty segments beyond 1 MB are returned to the OS

    3.13.3.5 Full Collection
    * Triggers:

    1. Failure to allocate memory / resource
    2. App moved to background
    3. OS going to hibernation
      * Process:
    4. Memory from Unreferenced Objects released
    5. Heap compacted
    6. All free segments released, including the 1 MB reserve

    Btw.:
    Es gibt viel zu wissen über den Garbage Collector. Viele dinge sind abhängig vom OS, Gerät und CPU. Solch pauschale Aussagen wie sie hier mit Nachdruck geworfen werden ohne das Zielsystem zu kennen finde ich ein wenig daneben (und kreide mir das auch gleich selbst an für die pauschale Aussage, das bei Generation 0 geräumt wird.)

    Und dann noch eine persönliche und Subjektive Meinung: Es ist sehr angenehm das man sich bei Schnittstellen nicht mehr Fragen muss, wer den Speicher aufräumt (wobei sich die Frage meist nur dann aufdrängte, wenn die Schnittstelle eine C Api war). Ansonsten fand ich die Mechanismen unter C++ definiert - irgendwie wusste man wann etwas freigegeben wurde und man konnte sich auch eines "Garbage Collectors" bedienen wenn man unbedingt wollte. Im .Net Framework (vorallem im Compact Framework) wird man vielen Regeln unterworfen. Zwar muss man sich seltener den Kopf über die Speicherverwaltung zerbrechen, aber wenn bekommt man gleich kräftige Kopfschmerzen dabei. (Siehe Beispiel für das Compact Framework).



  • Knuddlbaer, das ist beeindruckend. Wirklich. Und nein, ich kreide Dir nichts an. Dazu besteht kein Grund. Vielmehr bewundere ich Deine Hartnäckigkeit und Deinen Sinn fürs Detail. Was Du über Pauschalierungen sagst, finde ich richtig, sorry, wenn ich jemandem zu nahe getreten bin. Tatsache ist, dass wir alle viel zu wenig über den Code wissen, der die ganze Diskussion ausgelöst hat. Deshalb auch meine Unzufriedenheit mit dem o.p.

    Der GC tut was er tut meistens gut, wenn man die Möglichkeit hat, sollte man ihn in Ruhe lassen. Meine Vermutung war, dass der Code jedoch so angelegt ist, dass der GC gar nicht erst zum Zuge kommen kann. Dies könnte z.B. der Fall sein, wenn die im BackgroundWorker erstellten Objekte Finalizer implementieren und aus verschiedenen Gründen nicht in der Generation 0 oder 1 collectet werden können. Mehr noch, unter bestimmten Umständen (z.B. Referenzen auf globale Variable im Finalizer) könnten ungemanagte Ressourcen gar nicht erst richtig freigegeben worden sein. Da der Speicherverbrauch lt. Beschreibung von ABstraCT direkt proportional mit der Laufzeit zu sein schien, und eine durch Selbstaufruf verursachte StackOverflowException selten 5 Tage braucht (obwohl das durchaus vorkommt), darüber hinaus kein Hinweis auf eine entsprechende Exception durch den o.p gebracht wurde, blieb mir auch nichts anderes übrig als das zu schreiben, was ich geschrieben habe. Kommt keine Speicheranforderung, weil z.B. der WorkerThread schläft, kann auch der GC nicht viel machen, umso weniger als verwendete Instanz-Referenzen womöglich noch valide sind.

    Und damit das Ganze noch an Spannung gewinnt: Soviel ich weiß ist der GC für Anwendungen optimiert, die kurzlebige, kleine Objekte erstellen. Der GC collectet aus Performanz-Gründen keinen Speicher zurück der auf dem Large Object Heap aloziiert wurde:

    "Während der Prozessdauer nimmt der Large Object Heap immer zu, um alle gegenwärtig referenzierten Zuordnungen von großen Blöcken aufzunehmen. Er nimmt jedoch bei der Freigabe von Objekten niemals ab, selbst im Falle einer Garbage Collection nicht."

    (MSDN: Produktionsdebugging für .NET Framework-Anwendungen. Debuggen von Speicherproblemen).

    Sehr informativ fand ich folgenden Link zum GC, auch wenn der Beitrag in Stichwörter gehalten ist:
    http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry

    Ich verstehe nicht ganz, warum Du

    GC.WaitForPendingFinalizers();
    GC.Collect();
    

    gleich zweimal hintereinander aufrufst. Ein einziger Aufruf sollte reichen, um das Collecten der Objekte, deren Aufräumung durch Finalizer verzögert wurde, anzustoßen. Welche Überlegung steckt dahinter?

    Einen schönen Gruß.



  • Hallo,

    ok den Op hab ich jetzt ein wenig verdrängt und die Chance gesehen ein wenig über den GC zu Diskutieren, denn der bereitet mir Regelmässig Kopfschmerzen. (Ich denke auch, das der OP hier garnicht mehr mitliest.)

    Das Thema GC lässt sich schwer Diskutieren, vor allem Anonym in einem Forum bei dem man viel geschriebenes falsch aufnehmen kann. (Und Softwareentwickler gehören ja nicht unbedingt zu den Feinfühligen Menschen 😉

    Der Mehrfachaufruf des GC:

    Der Mehrfachaufruf war aus dem Experiment heraus zu versuchen eventuell auf dem vollen Framework das gleiche Verhalten zu erzeugen wie ich es unter dem Compact Framework habe. (Zu 70% arbeite ich unter dem Compact Framework.)

    Ich wollte sicherstellen, das nicht irgendwelche Objekte überleben weil ein Objekt der Generation 0 z.B. eine Referenz hält. (Ich wirklichkeit wird das aber nichts bringen, ich war einfach zu müde für das Detail. So wird nur mehrfach Generation 0 entfernt, die Generation 2, die eventuell eine Referenz auf ein Objekt der Generation 0 hält kratzt das herzlich wenig.)

    Für mich stellt sich nach wie vor die Frage:
    - In welchem Thread läuft der GC ? (Vorallem was das Compact Framework betrifft)
    - Ist der Heap pro Appilkation oder Systemweit ?
    - Wie stellt der GC sicher, das es wegen Fragmentierung zur Speicherknappheit kommt (wenn jeder Heap Pro Applikation ist.)
    - Kann mir das verhalten der CF Anwendung im vollen Framework auch passieren ? (Dann hätte ich Grundlegend etwas falsch verstanden was die Arbeit des GCs betrifft. Und das würde mir Sorgen bereiten gegenüber allen Projekten die bisher gelaufen sind.)

    Ich finde die Dokumentation teilweise verwirrend und widersprüchlich. An sich hatte mich das auch nicht gekratzt , bis ich die oben gezeigte CF Anwendung hatte, die plötzlich mit einer Object Disposed Exception aufwarten konnte wo meinem Verständnis nach garkeine hätte sein dürfen. Nun weiß ich nicht ob dies nur auf dem CF so ist oder ich grundlegend etwas falsch verstanden habe, also das Verhalten des GCs in dem Beispiel:

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace SmartDeviceProject1
    {
        public partial class Form1 : Form
        {
            test te = null;
            public Form1()
            {
                InitializeComponent();
                te = new test();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                te.Main();
            }
        }
    
        public class test
        {
            Graphics gr = null;
            public void Main()
            {
                if (gr == null)
                    gr = Graphics.FromImage(new Bitmap(1, 1));
                gr.MeasureString("Hallo Welt", new Font("Arial", 12,FontStyle.Regular));
                GC.Collect(); // Aufräumen erzwingen.        }
        }
    }
    

    völlig korrekt ist. Wenn ja, hätte ich etwas falsches Gelernt und würde mir gerne durch die Community ändern. Das ist aber nicht so einfach - neigt man doch dazu schnell auf eine Dokumentation zu verweisen bzw. davon auszugehen, das sich die "Gegenseite" nicht damit beschäftigt hat. Der GC scheint dann an sich noch ein merkwürdiges Thema zu sein, mehrere Diskussionen um den GC wurden sehr schnell beendet weil einfach keiner da war, der sich intensiev damit beschäftigt hat. (Sowas wie z.B. "Was totaler Unsinn ist weil die GC der .Net-Frameworks nicht durch Speicheranforderungen ausgelöst wird"). Zugegeben, man kann nicht alles wissen und lässt auch mal falsche Informationen los weil man es nicht besser wusste, aber über Destruktive Kommentare betreffend dem Thema GC bin ich nie weit gekommen :o(

    Lange rede - kurzer Sinn:

    Die Hoffnung des ganzen lag darin, das vllt. jemand sagen kann wie sich obige Fragen verhalten. Entweder weil ich es übersehen habe (Wald vor Bäumen nicht sehen) oder einfach mehr Wissen da ist. (Ich weiß z.B. nichts von Usermode und Kernelmode , erst recht nicht wie ich von einem Sleep dahin komme. Zu wenig Ahnung der Internas (die ja vom Framework an sich versteckt werden sollen.))

    [edit] C&P Fehler beseitigt[/edit]



  • Knuddlbaer, sollten wir nicht besser einen neuen Diskussions-Thread beginnen?

    Ausgehend von Deinem Code, vermute ich, dass Du Visual Studio 2008 verwendest. Weiterhin gehe ich davon aus, dass Deine Anwendung das Compact Framework 3.5 verwendet (Voreinstellung). Sollten meine Mutmassungen zutreffen, könnte Dein Problem vielleicht gelöst werden, indem Du ein neues Projekt erstellst und gleich im ersten Dialogfenster rechts oben ".NET Framework 2.0" statt ".NET Framework 3.5" auswählst. Anschließend kannst Du Deinen Code in das neue Projekt einfügen.



  • Eventuell ist ein Moderator so nett zu Splitten, ansonsten wäre es doof wenn man jetzt mittendrinn bricht. Mit dem Originalpost hat es eh nichts mehr zu tun, aber wenn man jetzt in einem neuen Thread weiter macht geht alles verloren für all jene, die später mal darauf stoßen.

    @Mod: Ist ein Splitten ab dem ewiglangen Quotepost machbar ?

    @maro

    Es ist ein CF2.0 Projekt. 3.5 hab ich ehrlich gesagt noch nicht getestet da derzeit kein 3.5 verwendet werden darf. (Vorgabe). Das Problem des nicht Verstehens löse ich aber auch nicht mit ner Combobox 🤡



  • Oops da habe ich ja was angestossen !

    also wie schon anfangs erwähnt wurde das problem gelöst da es sich um eine endlos rekursion meinesresits gehandelt hatte. (läuft jetzt auf nem speicherlevel und räumt sich auch auf, wenn man es minimalisiert dann fällt der resourcenverbrauch sogar total runter(das war vorher nicht der fall))

    aber mal ne andere frage da ich es auch woanders gelesen habe, soll man sleep oder Thread.sleep verwenden ? oder ist es egal ?

    CU



  • Woher nimmst Du denn sleep ? Ich wüsste nicht, das C# das als Schlüsselwort anbietet. Thread.Sleep würde ich vorziehen gegenüber dem unbekannten.

    Du solltest aber wirklich überlegen ob eventuel System.Threading.Timer nicht die elegantere Lösung ist.



  • wie anfangs erwähnt ist es ein VB programm und da gibt´s eben nen windows sleep:

    http://www.vbarchiv.net/vbapi/Sleep.php
    CU


Anmelden zum Antworten