Unter welchen Umständen kann eine OutOfMemoryException geworfen werden?



  • Danke ihr beiden, google hat massenweiße solcher Artikel, wobei oft keine konkreten ursachen beschrieben werden, ehr so (könnte sein):) Aber die Msdn Artikle sind schon konkreter;)

    Welche Informationen liefert mir den der Stacktrace einer OOM Excpetion? Ich weis zwar das an der Stelle die Exception geworfen wird, weil genau da Speicher allokiert werden muss etc. und BOOM! Aber es wäre ja auch interessant wie es bei parallel laufenden Processen/Threads aussieht, welche evtl. auch zu der Exception beitragen.
    Ich habe eine Ummanged COM Modul in meiner anwendung welche natürlch zur Speicherfragmentierung beiträgt, was dem GC evtl. Probleme bereitet.

    Zudem verwende ich WPF und darin WinFormHost Control. Könnte das ein Indiz sein?

    Ohje Ohje hehe;)



  • Ohne deine Applikation zu kennen kann man da wenig sagen.

    Eine Sache kannst Du mal prüfen:

    Für alle Klassen die IDisposeable implementieren solltest Du Dispose aufrufen wenn Du diese Objekte nicht mehr brauchst bzw. von Anfang an das using() benutzen, z.B.

    using (Graphics g = Graphics.FromHwnd(Handle))
    {
    }
    

    Ansonsten könnten memory-profiler helfen.



  • @NullBockException:
    Der Grund ist einfach dass dein Programm mehr Speicher verwendet, als für ein .NET Programm gut ist, wenn es in einem 32 Bit Prozess läuft.
    600MB sind halt schon grenzwertig.



  • hustbaer schrieb:

    @NullBockException:
    Der Grund ist einfach dass dein Programm mehr Speicher verwendet, als für ein .NET Programm gut ist, wenn es in einem 32 Bit Prozess läuft.
    600MB sind halt schon grenzwertig.

    640kByte sind ausreichend für einen Rechner (oder so ähnlich)



  • Was hat das jetzt mit irgendwas zu tun?



  • Hmm eine .NET Applikation darf 2GB verbrauchen. Die 600MB kommen nicht von irgendwoher, die werden einfach benötigt (momentan). Vll. kann ich noch optimierungen vornehmen und mit nem Profielr schaun wo oft und viel speicher angefrodert wird, welche evtl. nur kurzfristig benötigt wird.



  • hustbaer schrieb:

    Was hat das jetzt mit irgendwas zu tun?

    die Aussage stammt irgendwann mal von Herrn Gates - wo liegen wir jetzt? ... Deine Aussage ist irgendwie gleich mehr als 600 MB braucht ein Programm nicht - merkt Dir mal Deine Aussage und schau da in 10 Jahren nochmal drüber



  • mogel schrieb:

    hustbaer schrieb:

    Was hat das jetzt mit irgendwas zu tun?

    die Aussage stammt irgendwann mal von Herrn Gates - wo liegen wir jetzt? ... Deine Aussage ist irgendwie gleich mehr als 600 MB braucht ein Programm nicht - merkt Dir mal Deine Aussage und schau da in 10 Jahren nochmal drüber

    Ja, ich kenne das Zitat.
    Bloss hast du was ich geschrieben habe überhaupt nicht verstanden.

    Ich sage nicht dass 600MB genug für irgendwas wären, oder sein sollten, oder sonstwas in der Richtung.

    Ich sage bloss, dass man sich als Programmierer niemals erwarten sollte, dass man mit einem .NET Programm, welches unter 32 Bit läuft, mehr als 600MB verwenden kann. Weil es ab so ~800MB einfach auf genügend Systemen bei genügend Programmen Probleme gibt. Das ist ein Erfahrungswert. Und den zu ignorieren halte ich nicht für sinnvoll.

    Jetzt klarer?

    ----

    Klar kann man immer Schuldige suchen, vielleicht findet man sogar welche, und vielleicht kann man sogar ein paar huntert MB mehr rausholen. Bloss was bringt das? Nach ein paar Tagen/Wochen/Monaten steht man wieder an. Lieber gleich auf 64 portieren. Oder, alternativ, zusehen, dass man den Speicherbedarf um grössenordnungen runterbringt, damit das ganze noch skalieren kann.



  • NullBockException schrieb:

    Hmm eine .NET Applikation darf 2GB verbrauchen. Die 600MB kommen nicht von irgendwoher, die werden einfach benötigt (momentan). Vll. kann ich noch optimierungen vornehmen und mit nem Profielr schaun wo oft und viel speicher angefrodert wird, welche evtl. nur kurzfristig benötigt wird.

    Hier kann es auch drauf ankommen wie Du den Speicher benutzt. die GC von .NET verwaltet den Speicher in sogenannten Generationen. Kurzfristige Objekte bleiben in der ersten Generation und werden meist sofort wieder abgebaut. Identifiziert die GC ein Objekt als "langlebig" wandert dies in eine höhere Generation und wird dann seltener "Collected". Objekte in Generation 0 werden bei jedem GC-Lauf Collected, Objekte in Generation 1 nur noch ab und zu (z.B. jeder 10ter Lauf oder so, ka wie genau) und Objekte in der höchsten Generation werden bis zum Ende des Programms gar nicht mehr collected.

    Als Langlebig gilt ein Objekt wenn es eine bestimmte Anzahl von Gc-Läufen überlebt hat. Das kann aber für Dich zum Problem werden wenn Du durch hohen Speicherbedarf sehr viele Objekte anlegst und wieder zerstörst, da dadurch mehr GC-Läufe getriggert werden. In einem solchen Scenario können Objekte als langlebig identifiziert werden die es eigendlich nicht sein sollten.

    Ob das passiert kannst Du testen indem Du mal bei Objekten die Generation checkst: GC.GetGeneration(object obj) Wenn da Objekte, die Deiner Meinung nach kurzlebig sein sollten nicht in "0" sind sondern 1 oder höher hast Du einen möglichen Grund für Dein Problem.



  • @loks:
    Soweit ich weiss wird immer eine volle Collection getriggert, bevor eine OutOfMemoryException geworfen wird. Von daher verstehe ich nicht, wie die Verteilung der Objekte auf die einzelnen Generationen einen Effekt darauf haben sollte, wann und ob eine OutOfMemoryException geworfen wird. Der Effekt kann IMO nur sein, dass das Programm langsamer läuft, als es "nötig" wäre.



  • hustbaer schrieb:

    @loks:
    Soweit ich weiss wird immer eine volle Collection getriggert, bevor eine OutOfMemoryException geworfen wird. Von daher verstehe ich nicht, wie die Verteilung der Objekte auf die einzelnen Generationen einen Effekt darauf haben sollte, wann und ob eine OutOfMemoryException geworfen wird. Der Effekt kann IMO nur sein, dass das Programm langsamer läuft, als es "nötig" wäre.

    In der Theorie stimme ich Dir da zu. In der Praxis hatte ich selbst schon einen Fall wo eine OutOfMemoryException geworfen wurde obwohl eigendlich nur temporäre Objekte erzeugt wurden. In dem konkreten Fall konnte ein GC.Collect() innerhalb der Schleife die Exception verhindern, was darauf hindeuted das bei erzwungenem full-collect mehr Speicher abgeräumt wurde. (Natürlich auf Kosten der Performance).

    Natürlich war GC.Collect() nicht die Lösung, aber es half das Problem zu verstehen. Code ein wenig umgestellt, macht unterm Strich immer noch das gleiche, nur ohne Exception.


Anmelden zum Antworten