Hallo.
Ich bin im Rahmen eines sehr großen .NET Projektes auf ein Problem gestoßen, zu welchem mir im Moment jeder Lösungsansatz fehlt.
Unser Programm bekommt einer (stetig) größer werdende Datei übergeben, welche verarbeitet werden muss (Anfangsgrößen um die 70 MB).
Dies geschieht regelmäßig (bis zu 2 Mal pro Stunde). Das Programm soll/muss eigentlich durchlaufen.
Aber: der Speicherverbrauch explodiert, bis es das Programm oder den ganzen Rechner entschärft.
Im Process Explorer sowie im ANTS Memory Profiler bin ich darauf gestoßen, dass das Programm sehr viel Speicher reserviert hat, der Status dessen aber auf "unused" steht. Der Profiler zeigt, dass das Programm z.B. 890 MB RAM reserviert hat, davon aber nur 40 MB wirklich genutzt, der Rest liegt brach und wird nicht an das Betriebssystem zurück gegeben.
Nun dachte ich zuerst an ein Speicher-Leck (wir arbeiten viel mit eigenen Dispose-Routinen). Aber nach einigem Testen mit dem Profiler kann ich das ausschließen.
Schaue ich mir die Speicherbelegung an, sehe ich, dass der größte Teil des Speichers für den LOH reserviert ist.
Nach einigen Recherchen bin ich auf folgende Webseiten gestoßen:
- The Dangers of the Large Object Heap
- Large Object Heap Uncovered
.
Vom Prinzip her dürfte das genau das Problem sein. Das Programm packt die Daten in den LOH. Diese werden im Dispose frei gegeben, es entsteht eine Lücke. Die nächsten Daten sind zu 99,9% minimal größer, passen also nicht in die vorhandene Lücke - und es wird neuer Speicher angefordert. Das schauckelt sich dann immer weiter hoch.
Ich kann den GC ja minimal steuern, z.B. zu einem Collect zwingen. Aber ich habe nichts gefunden, ob es möglich ist, den Speicher im LOH zusammen zu fassen, damit das Programm den freien Speicher (in den vielen Lücken dazwischen) wieder frei gibt.
Geht das überhaupt? Oder ist man hier dem .NET Speichermanager auf gedeih und verderb ausgeliefert?
Ich bin im Rahmen eines sehr großen .NET Projektes auf ein Problem gestoßen, zu welchem mir im Moment jeder Lösungsansatz fehlt.
Unser Programm bekommt einer (stetig) größer werdende Datei übergeben, welche verarbeitet werden muss (Anfangsgrößen um die 70 MB).
Dies geschieht regelmäßig (bis zu 2 Mal pro Stunde). Das Programm soll/muss eigentlich durchlaufen.
Aber: der Speicherverbrauch explodiert, bis es das Programm oder den ganzen Rechner entschärft.
Im Process Explorer sowie im ANTS Memory Profiler bin ich darauf gestoßen, dass das Programm sehr viel Speicher reserviert hat, der Status dessen aber auf "unused" steht. Der Profiler zeigt, dass das Programm z.B. 890 MB RAM reserviert hat, davon aber nur 40 MB wirklich genutzt, der Rest liegt brach und wird nicht an das Betriebssystem zurück gegeben.
Nun dachte ich zuerst an ein Speicher-Leck (wir arbeiten viel mit eigenen Dispose-Routinen). Aber nach einigem Testen mit dem Profiler kann ich das ausschließen.
Schaue ich mir die Speicherbelegung an, sehe ich, dass der größte Teil des Speichers für den LOH reserviert ist.
Nach einigen Recherchen bin ich auf folgende Webseiten gestoßen:
- The Dangers of the Large Object Heap
- Large Object Heap Uncovered
.
Vom Prinzip her dürfte das genau das Problem sein. Das Programm packt die Daten in den LOH. Diese werden im Dispose frei gegeben, es entsteht eine Lücke. Die nächsten Daten sind zu 99,9% minimal größer, passen also nicht in die vorhandene Lücke - und es wird neuer Speicher angefordert. Das schauckelt sich dann immer weiter hoch.
Ich kann den GC ja minimal steuern, z.B. zu einem Collect zwingen. Aber ich habe nichts gefunden, ob es möglich ist, den Speicher im LOH zusammen zu fassen, damit das Programm den freien Speicher (in den vielen Lücken dazwischen) wieder frei gibt.
Geht das überhaupt? Oder ist man hier dem .NET Speichermanager auf gedeih und verderb ausgeliefert?
Comment