Laden...

Speicherproblem: Out of Memory

Letzter Beitrag vor 14 Jahren 28 Posts 8.033 Views
Speicherproblem: Out of Memory

Hallo,

ich habe ein dreidimensinales long Array mit folgender Dimensionierung addressiert:
x = variabel
y = 47
z = 10

Hatte bis gestern 1024 MByte Arbeitsspeicher und habe damit x auf ca. 150000 setzten können. Danach kam eine Out of Memory Meldung.

Soweit so gut. Seit heute habe ich vier Gigabyte Arbeitsspeicher. Die Fehlermeldung kommt nun bei knapp über x = 200000. Das enttäuscht und verwirrt mich irgendwie. Wenn ich mit 4 Byte pro long Eintrag rechne, komme ich bei x=250000 zu einem Speicherbedarf von ca. 450 MByte. Da sollte doch bei vier Gig Arbeitsspeicher deutlich mehr drin sein. Oder hat C# interne Beschränkungen?

Gruß

Hallo lebes,

ein long ist 8 Byte groß. Von den 4GB Hauptspeicher werden vermutlich nur 2 für Anwendungsprogramme verwendet (man kann das auf 3GB steigern). Damit sollte trotzdem noch ein bisschen mehr als 200000 drin sein (warum das nicht der Fall ist, weiß ich auch nicht), aber auch nicht endlos mehr.

herbivore

Danke für die Infos.

Wie kann man denn die Reservierung für Anwendungprogramme auf drei Gigabyte steigern?

Gibt es eine Möglichkeit sich die aktuelle Speicherbelegung eines C# Programmes anzeigen zu lassen?

Gruß

Habe eben die Programmausführung im Task Manager beobachtet. Beim Start des Programmes liegt die Speicherbelastung bei ca. 150MByte. Dann wird sukzessive das Array gefüllt und der Speicherbedarf steigt stetig auf ziemlich genau ein Gigabyte. Scheinbar reserviert das Programm nur genau diesen einen Gigabyte.

Wenn ich nun in der Systemleistung nachschaue, wird mir ein noch verfügbarer Speicher von fast zwei Gigabyte angezeigt.

Ist das hier eine generelle C# Beschränkung (zB wegen Garbage Collector oder ähnlichem) oder kann man die Speicherreservierung manuell erhöhen?

Original von herbivore
ein long ist 8 Byte groß. Von den 4GB Hauptspeicher werden vermutlich nur 2 für Anwendungsprogramme verwendet (man kann das auf 3GB steigern). Damit sollte trotzdem noch ein bisschen mehr als 200000 drin sein (warum das nicht der Fall ist, weiß ich auch nicht), aber auch nicht endlos mehr.

herbivore

Das stimmt für .NET nicht ganz. die runtime nutzt zwar 2GB aber davon stehen nur 1.2GB der Anwendung zu verfügung (der Rest wird als puffer zum verschieben von Objekten im Speicher vorgehalten).
Es gibt iregendeine einstellung um .NET 3GB nutzen zu lassen, ich weis aber nicht mehr wie das ging...

Die aktuelle Speicherauslastung kannst du mit dem Performance Monitor (Start->Run->Perfmon) anschauen (sowohl .NET als auch WIN32-Prozess spezifisch).

Bei deienem Monster-Array solltest du überlegen, ob du evtl. nicht auf Memory Mapped Files umsteigst. Damit kann man die Speichernutzung auf eine Page zur Zeit begrenzen (default 64kb).

Weiß hier jemand wie ich die Speicherbegrenzung auf 3GB hochsetzen kann?

Was sind Memory mapped Files? Das "Monsterarray" wird im Verlauf einer Simulation gefüllt. Daher ist die Sache auch "zeitkritisch". Wenn Memory mapped Files die Daten immer wieder von der Festplatte lesen müssen, wird mir wahrscheinlich nicht geholfen sein,-)

Gruß

Original von lebes
Was sind Memory mapped Files? Das "Monsterarray" wird im Verlauf einer Simulation gefüllt. Daher ist die Sache auch "zeitkritisch". Wenn Memory mapped Files die Daten immer wieder von der Festplatte lesen müssen, wird mir wahrscheinlich nicht geholfen sein,-)

Das bekannteste Memory Mapped File dürfte wohl das Page File sein (da landet dein Array eh früher oder später....).

Im prinzip wird bei einem Memory Mapped File immer ein Breiech einer Datei direkt in den Speicher gemapped. Geschrieben werden änderungen erst nach einem getriggerten Flush (quasi ein commit). (Der IIS Schreibt seine Logs so, daher sind die auch immer ein vielfaches von 64kb groß)

Die Frage die sich stellt ist, wie musst du die daten später verarbeiten?
Geht es erstmal "nur" um das Sammeln der Daten in Echtzeit?
Oder musst du während des Sammelns auch dynamische berechnungen anstellen (spich: alle Elemente lesen...)?

Wenn es "nur" um das Sammeln geht, kannst du auch einen gepufferten FileStream nehmen....

Oder direkt in eine Datenbank schreiben? Auch das kann man ja puffern und optimieren....

Hallo lebes,

Weiß hier jemand wie ich die Speicherbegrenzung auf 3GB hochsetzen kann?

das ist auf jeden Fall eine Windows- und keine .NET-Einstellung. Und wenn man windows 3GB bei google eingibt, ist enthält der erste Treffer schon die Lösung.

herbivore

PS: Eine weitere Lösung für dein Speicherproblem könnten sparse Arrays sein.

Vielen Dank für die Infos!-)

@herbivore: Bei mir bietet mir Google ein Samsung Notebook mit 3 GB Festplatte an erster Stelle an😉 Kannst du mir evt. den genauen Link schicken?

Habe jedenfalls jetzt so ein paar Infos gefunden. Wenn ich das richtig verstehe, muss ich kleine Änderungen in der Boot.Ini Datei durchführen (wofür ich sicherlich Adminrechte brauche, oder? ). Ist es damit dann getan oder muss ich speziell in der Visual Studio Umgebung noch Einstellungen ändern?

Gruß

Hallo lebes,

Bei mir bietet mir Google ein Samsung Notebook mit 3 GB Festplatte an erster Stelle an😉

hm, dann scheinst du ein anderes google zu benutzen als ich.

Kannst du mir evt. den genauen Link schicken?

Mein erster Treffer ist http://www.administrator.de/mit_Windows_XP_(32bit)bis_zu_3GB_RAM_f%FCr_Software_nutzen(3GB_Switch).html, aber soweit ich das gesehen habe, gibt es endlos Seiten, die entsprechenden Hinweise geben.

herbivore

OK, einer der SysAds hier hat mir eben mitgeteilt, dass er die (auf den entsprechenden Links beschriebenen) Änderungen in der Boot.Ini Datei durchgeführt hat.

Habe also meinen Rechner runtergefahren, neugestartet und es nochmal ausprobiert. Leider hat sich an der Situation nichts geändert. Kriege immer noch diese OutofMemoryException.

Vermute daher, dass man zusätzlich in Visual Studio bestimmte Veränderungen durchführen muss. Irgendjemand eine Idee was ich an den SysAd weiterleiten könnte?

Gruß

Mit Visual Studio hat das auf keinen Fall etwas zu tun - wenn dann musst du schon die machine.config anpassen, aber dass sich darin eine Lösung des Problems verbirgt, unwahrscheinlich.

Vielleicht solltest du lieber versuchen, mit weniger Speicherbedarf auszukommen und Teile auf die Festplatte auszulagern...

... ansonsten könnte der Wechsel auf ein 64Bit-System die Lösung deiner Probleme sein: Eigentlich sollte auch .Net auf einem solchen System mehr als 4GB verwenden können und auch diese magische 2GB Hürde sollte demnach nicht mehr existieren!

Habe jetzt schon einige Male von dieser "magischen" 2 GB Grenze gelesen. Bei mir steigt das Programm (laut Task Manager) allerdings schon bei knapp über einen GB aus. 2GB würde mir auch schon sehr helfen.
Wie könnte man vorgehen um rauszufinden, warum er bei mir schon bei 1GB aussteigt? Ideen?

Werde auf jeden Fall den SysAd jetzt erstmal schreiben, dass es noch nicht funktioniert und mal sehen, ob er noch Ideen hat.

Gruß

Original von lebes
Habe jetzt schon einige Male von dieser "magischen" 2 GB Grenze gelesen. Bei mir steigt das Programm (laut Task Manager) allerdings schon bei knapp über einen GB aus. 2GB würde mir auch schon sehr helfen.
Wie könnte man vorgehen um rauszufinden, warum er bei mir schon bei 1GB aussteigt? Ideen?

Wie schon gesagt, unter .NET hast du "nur" 1,2GB von den 2GB zur effektiven verfügung. Den rest braucht das Framework als Puffer.

Wenn du allerdings dem Framework 3GB gibst steigt der nutztbare Speicher auch mit an.

Allerdings solltest Du wirklich prüfen, ob dein Design wirklich optimal ist. Durch dieses riesen Array wird Windows eh wie wilde pagen und auslagern (ausser du schaltest die Auslagerungsdatei komplett aus).
Daher hast du auch eine ganze menge Platten I/O, so dass es evtl. sinnvoller ist, den selber zu steuern....

Habe nun in einem Windows XP Forum die Frage platziert. Die zwei GB Grenze existiert so und vermutlich kriege ich nur knapp über einen GB, weil es ja noch diesen Puffer gibt.

Prinzipiell sollte es auch ausreichen die Veränderungen der Boot.Ini durchzuführen um die 3GB Option zu aktivieren. Nur leider hat das hier bisher nicht zum Erfolg geführt.

Ein weiterer Hinweis dort war, dass man was an den Compileroptionen ändern müsste:
"Eine 32-bittige App kann

  • unter 32bittigem Win mit /3GB Switch bis zu 3GB allozieren
  • unter 64bittigem Win bis zu 4GB allozieren
    wenn gleichzeitig das LARGEADDRESSAWARE Flag bei dieser App
    (Linker-Switch) gesetzt ist. "

Dann war da noch die Rede, dass es auch ein wenig davon abhängt wie groß die Happen sind, die man jeweil alloziiert.

Meine Frage ist nun wie ich in Visual Studio Linker bzw. Compiler Optionen setzten kann. Vielleicht ist das ja tatsächlich momentan noch mein Problem.

Über die Variante mit der manuellen Zwischenspeicherung denke ich momentan auch ernsthaft nach (auch wenn ichs lieber vermeiden möchte). Allerdings möchte ich jetzt (wo ich schon einiges an Zeit reingesteckt habe) auch das Problem mit der 3GB Grenze gelöst kriegen.

Gruß

Schön das die .Net Compiler gar keinen Linker mehr haben 😉

Der C++ Linker hat dieses LARGEADDRESSAWARE Flag, aber wie dem auch sei, in C# kannst du damit eh nichts anfangen weil dort die Runtime alles macht und nicht der Linker.

Baka wa shinanakya naoranai.

Mein XING Profil.

Das heißt soviel wie: Daran liegt es nicht, dass ich nur 1GB kriege???

Deswegen schrieb ich, dass sich an der machine.config evtl. noch etwas drehen lässt - wahrscheinlich aber eher nicht...

Original von lebes

Prinzipiell sollte es auch ausreichen die Veränderungen der Boot.Ini durchzuführen um die 3GB Option zu aktivieren. Nur leider hat das hier bisher nicht zum Erfolg geführt.

Hallo,

mit der /3GB Option kann man ja bekanntlich einer Applikation einen maximal verfügbaren User space von 3 GiB geben. Allerdings wirst du dennoch kein Array erzeugen können welches eine derartige Dimension hat, da das zusätzlich GB welches der Switch freischaltet nicht direkt an den Speicherblock der üblichen 2 GB angrenzt. Ein Array benötigt allerdings zusammenhängenden Speicher.

Grüsse, Egon

Das klang zunächst sehr gut. Habe es eben ausgetestet und zunächst einfach zwei Arrays deklariert, was direkt zur gleichen Fehlermeldung führte.

Dauraufhin habe ich es noch mit fünf Arrays versucht. Leider ebenfalls erfolglos. Es bleibt bei der gleichen "maximalen" Gesamtgröße.

Es liegt also scheinbar nicht daran, dass alles innerhalb eines Arrays gespeichert wird.

Gruß

Hallo lebes,

wieso verfolgst du nicht die alternativen Vorschläge?

herbivore

Wahrscheinlich hängt das Phänomen mit der Speicherfragmentierung zusammen: Die .Net Runtim kann einfach nicht genügend zusammenhängenden Speicher reservieren, damit es passt...

So ich geh jetzt erstmal ins Wochenende. Heute konnte ich mich leider garnicht mit dem Problem beschäftigen.

Die weiteren Vorschläge sind sicher gut und so wies ausschaut wird mir nichts weiter übrig bleiben, als die Daten zwischenzuspeichern. Was allerdings vermutlich schon zeitkritisch ist, da ich hinterher bei der Auswertung vielfach "sequentiell" die Array-Informationen brauche.

Ärgerlich ist natürlich, dass ich jetzt hier vier GB Speicher durchgeboxt habe und es nur "relativ" wenig Zusatznutzen bringt.

Da ich jetzt keine weiteren Ideen mehr erhalten habe, könnte es durchaus sein, dass es an einer prinzipiellen .net Beschränkung liegt.

Schönes Wochenende.

Gruß

Eine blöde Idee noch am Rande...

Schreib dir doch eine native (C++) Dll, die dir ein 3GB großes array erlaubt?
Dann unsafe direkt darauf zugreifen?
Oder gar direkt Unmanaged / unsafe Speicher allozieren? Das sollte doch gehen (GlobalAlloc ausserhalb des GC).

Ist nicht gerade der .NET-Weg, aber wenn's nun garnicht anders geht?

Ich kenne jemanden der eine komplette Textverarbeitung in "1-2-3" geschrieben hat.

Geht alles, ist nur das falsche Werkzeug.

Auch .NET ist nicht für alles die beste Lösung, und es dann mit Bieben und Brechen
hinzubekommen ist meist nicht sinnvoll.

Hallo,

ich habe nun auch festgestellt dass ich für meine soft. lediglich 1.2gb zur Verfügung habe, bis eine OutOfMemory Exception ausgelöst wird.

Kann man diese Grenze irgendwie verschieben?

Vom System her, habe ich einen Industrierechner mit 4gb ram (werden nur 3 genutzt von winxp pro).

In der Software werden sehr große bilder verarbeitet, deshalb kann es kurzfristig zu so hohem Speicherverbrauch kommen.

Ich möchte wie gesagt nur wissen ob/wie man diese magische grenze von 1,2GB erhöhen kann und nicht wie man den Speicherverbrauch in einer Applikation minimiert.

Danke im Voraus.

MFG
Steffen

Hallo steffen_dec,

Kann man diese Grenze irgendwie verschieben?

nur durch die Verwendung von 64bit. Für 32bit gilt:

ich habe nun auch festgestellt dass ich für meine soft. lediglich 1.2gb zur Verfügung habe, bis eine OutOfMemory Exception ausgelöst wird.

Eigentlich kann ein Prozess bis zu 2GB bekommen, aber durch Fragmentierung des Speichers, insbesondere wenn du große Objekte (wie eben diene Bilder) anlegst, kann deutlich früher Schluss sein.

Also noch mal: Es hilft nur, auf ein 64bit-Betriebssystem umzusteigen.

herbivore

Also noch mal: Es hilft nur, auf ein 64bit-Betriebssystem umzusteigen.

Oder (zusätzlich) eine unmanaged Sprache wie C(++) verwenden. Dort kannst du die Verwaltung des Speichers deinen entsprechenden Bedürfnissen beinahe beliebig anpassen und somit das Optimum rausholen.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...