Laden...

Speicherbedarf einer Anwendung steigt ständig an

Erstellt von JCDenton vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.256 Views
JCDenton Themenstarter:in
73 Beiträge seit 2007
vor 15 Jahren
Speicherbedarf einer Anwendung steigt ständig an

Hallo Zusammen,

ich habe mal wieder ein Problem. Ich habe eine Rekursion, die mir alle Dateien in einer Ordnerstruktur behandeln soll. Die Struktur ist ungefähr so:*Der Startordner enthält ca. 256 Unterordner *diese Unterordner haben wiederum 256 Unterordner *und diese nochmal 256 Unterordner, *wo die zu behandelnden Dateien liegen. *Es sind nicht immer exakt 256 Unterordner. *Es sind auch nicht exakt 256 Dateien in den untersten Ordnern, *aber die Dateien kommen nur in den untersten Ordnern vor.

Meine Rekursion:


//suche nach Dateien
String[] files = Directory.GetFiles(path);

//für alle Dateien
foreach (String file in files)
{
      //Dateien behandeln
      this.MainProcess(file);
}

// Ordner holen  
String[] directories = Directory.GetDirectories(path);

//Ordner rekursiv durchgehen
for (int i = 0; i <= directories.GetUpperBound(0); i++)
{
      //Aufruf der Rekursion
      RecursiveDirectorySearch(directories[i]);
}

Soweit sogut, meine Rekursion funktioniert, aber nach ca. zwei Stunden hat sich meine Anwendung bereits 100 MB Speicher genommen (wird auch langsamer) und verlangt nach mehr 😉. Über Nacht ist meine Anwendung sogar abgestürzt. Ich konnte leider keine Fehlermeldung sehen, da früh eine Sicherung rausgeflogen ist. Aber ich vermute ganz stark, dass sich die Anwendung vollgefressen hat und dann geplatzt ist.

Ich habe auch schon einige Beiträge im Forum, die Memory Leaks behandeln (z.B.: MemoryLeaks / nicht abgehängte Events) oder sich mit Stack Overflows (z.B.: Irrgartengenerator: StackOverflow) beschäftigen, gelesen. Dabei habe ich mitgenommen, dass der GC eigentlich gut arbeitet, aber man sich nicht drauf verlassen soll.

Wie kann ich meine speicherhungrige Anwendung abspecken?1.Ist meine Rekursion irgendwie verkehrt bzw. offensichtlich falsch programmiert? 1.Sollte ich eher eine while-Schleife verwenden? Das mag bei meiner Rekursion wohl nicht so schwer sein, kann aber eigentlich nicht die Lösung sein. 1.Bringen Destruktoren, die globale Variablen in den Klassen auf null setzen, etwas? 1.Worauf sollte ich sonst noch achten?

Es wäre schön, wenn mir der ein oder andere ein paar Hinweise geben kann =).

JCDenton

1.002 Beiträge seit 2007
vor 15 Jahren

Hallo JCDenton,

Rekursion beansprucht den Stack extrem stark. Edit: Gemeint ist die Verwendung von Rekursion im gezeigten Link ...
s. Irrgartengenerator: StackOverflow => 8 Minuten alt 😉 ...

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

L
862 Beiträge seit 2006
vor 15 Jahren

Versuch mal sowas in der Art:



Auflistung<string> directories = ...;

while(directories.Count > 0)
{
  directories.AddRange(aktuellesElement.GetDirectories());
  foreach(File file in aktuellesElement)
  {
    irgendwas(file);
  }
}


Die Klassennamen/Methoden sind natürlich nicht korrekt aber wenn du es nach diesen Prinzip machst sparst du dir die Rekursion.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo JCDenton,

deine Rekursion geht nur über wenige Ebenen. Daher sollte das Problem nicht in der Rekursion liegen, sondern in der eigentlichen Verarbeitung (MainProcess). Du musst also weder auf die Rekursion verzichten noch die Schleifen ändern.

Wenn Objekte IDisposable implementieren, rufe möglichst früh Dispose auf. Ansonsten könnten nicht abgehängte EventHandler ein Problem sein. Von diesen beiden Ausnahmen abgesehen, kannst du dich auf den CG verlassen.

Hallo m0rius,

Rekursion beansprucht den Stack extrem stark.

das lässt sich nicht pauschalisieren und ist im konkreten Fall nicht so.


>
=> 8 Minuten alt 😉 ...

Und JCDenton trotzdem schon bekannt gewesen, wenn du dir seinen Beitrag genau anschaust. 😃

herbivore

2.082 Beiträge seit 2005
vor 15 Jahren
  
Auflistung<string> directories = ...;  
  
while(directories.Count > 0)  
{  
  directories.AddRange(aktuellesElement.GetDirectories());  
  foreach(File file in aktuellesElement)  
  {  
    irgendwas(file);  
  }  
}  
  
  

Wird nie enden, da die Elemente in directories nie Reduziert/überschrieben werden und einen break gibts auch nirgends. Oder übersehe ich da etwas?

Es ist toll jemand zu sein, der nichts von der persönlichen Meinung Anderer hält. - frisch-live.de

1.002 Beiträge seit 2007
vor 15 Jahren

Hallo herbivore,

ich hatte trotzdem vermutet, dass es an der Rekursion liegt, und deshalb nochmal auf den Thread verwiesen, in dem die Lösung per Iteration gezeigt ist. Und da der - recht lange - Beitrag um 12:03 geschrieben wurde, zommis Lösung hingegen erst um 12:00, gehe ich nicht davon aus, dass JCDenton diese bereits gesehen hat.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo m0rius,

ich hatte trotzdem vermutet, dass es an der Rekursion liegt, und deshalb nochmal auf den Thread verwiesen, in dem die Lösung per Iteration gezeigt ist.

hier geht es aber nicht Rechtsrekursion und daher kann man die Rekursion auch nicht auf die gleiche Weise umsetzen, wie in deinem Thread.

Grundsätzlich kann man man natürlich jede Rekursion in eine Iteration umsetzen, aber dass ist im konkreten Fall weder nötig noch sinnvoll.

herbivore

JCDenton Themenstarter:in
73 Beiträge seit 2007
vor 15 Jahren

Hallo m0rius,

ich hatte trotzdem vermutet, dass es an der Rekursion liegt, und deshalb nochmal auf den Thread verwiesen, in dem die Lösung per Iteration gezeigt ist. Und da der - recht lange - Beitrag um 12:03 geschrieben wurde, zommis Lösung hingegen erst um 12:00, gehe ich nicht davon aus, dass JCDenton diese bereits gesehen hat.

ja, ich hatte die Lösung noch nicht gelesen, aber da es, wie herbivore schon gesagt hat, nicht direkt an der Rekursion zu liegen scheint, ist das nun auch egal 😉. Trotzdem danke für den Hinweis.

Hallo herbivore,

deine Rekursion geht nur über wenige Ebenen. Daher sollte das Problem nicht in der Rekursion liegen, sondern in der eigentlichen Verarbeitung (MainProcess). Du musst also weder auf die Rekursion verzichten noch die Schleifen ändern.

soweit ich das bis jetzt beurteilen kann, hast du damit recht, das Problem liegt nicht dan der Rekursion. Innerhalb von MainProcess habe ich für jede Datei in meiner Rekursion zwei Linq-Objekte verwendet, aber diese Linq-Objekte nie disposed. Das habe ich nun geändert und siehe da, nach ca. einer Stunde dümpelt meine Anwendung konstant bei 25 - 28 MB herum 😉 und die CPU hat weitaus weniger zu tun.

Danke herbivore.

Wenn Objekte IDisposable implementieren, rufe möglichst früh Dispose auf. Wie finde ich das heraus? Bei jedem Objekt, dass nicht von meiner Klasse ist, schauen, ob es die ein **Dispose() **hat, oder wie ist das allgemeine Vorgehen bei so etwas?

L
862 Beiträge seit 2006
vor 15 Jahren
  
Auflistung<string> directories = ...;  
  
while(directories.Count > 0)  
{  
  directories.AddRange(aktuellesElement.GetDirectories());  
  foreach(File file in aktuellesElement)  
  {  
    irgendwas(file);  
  }  
}  
  
  

Wird nie enden, da die Elemente in directories nie Reduziert/überschrieben werden und einen break gibts auch nirgends. Oder übersehe ich da etwas?

Gehe davon aus dass es sich bei der Auflistung um eine Queue handelt. Dort werden die Elemente beim abrufen aus der Collection entfernt.

Es handelt sich bei dem code aber wie gesagt eh nur um die Grundvorgehensweise und ist natürlich nicht lauffähig.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo JCDenton,

Wie finde ich das heraus? Bei jedem Objekt, dass nicht von meiner Klasse ist, schauen, ob es die ein Dispose() hat, oder wie ist das allgemeine Vorgehen bei so etwas?

ja, entweder nach der Dispose-Methode schauen oder in der Doku der jeweiligen Klasse, ob IDisposable implementiert wird.

herbivore

3.971 Beiträge seit 2006
vor 15 Jahren

Es liegt definitiv nicht an der Rekursion. Der Stack ist standardmäßig 1MB groß, sobald dieser Wert überschritten wird, wird eine StackoverflowException ausgelöst und das Programm sofort beendet. Steigende Hauptspeichernutzung (Heap) hat meist die Ursache einer falschen oder verspätende Speicherfreigabe (Destruktor/Finalizer) von teuren Objekten und nicht durch die Verwendung einer Rekursion!

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