Autor Beitrag
erther
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Do 25.03.10 12:46 
Hallo,

ich habe folgendes Problem. Ich verwende List<T> mit T=string und lese in einer Schleife eine Datei Zeilenweise aus, die ich in die Liste speichere. Die Datei (bzw. Dateien) sind teilweise echt lang und ich bekomme System out of Memory.

Was kann ich tun? Besteht bei List<T> eine Beschränkung?

Vielen Dank für die Hilfe!
erther
bakachan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 503
Erhaltene Danke: 34

W7 (x64) Ultimate
C# / VB.NET (VS2010 Ultimate)
BeitragVerfasst: Do 25.03.10 13:12 
List<T> hat soweit ich weiss keine Beschränkung was die Größe angeht also wird wohl der RAM deines Systems voll sein (wie die Fehlermeldung ja auch besagt).
erther Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Do 25.03.10 13:36 
Wenn ich die Elemente aus der Liste haue sobald ich sie nicht emhr brauche und dann erst neue Elemente einfüge, sollte das Problem behoben sein?!
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Do 25.03.10 14:44 
Hallo,

ich denke nicht, dass bei einer normale Verwendung von List<T>es zu einem System out of Memory kommt. Für sowas gibt es paging/swapping etc.
Was bedeutet das die Datei teilwese echt lang sind? Für meine Diskette sind 500kb ne Menge Holz :D

Und zeig mal bitte Code vom einlesen, ich vermute du hast da einen Programmierfehler.

Gruß
erther Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Do 25.03.10 16:41 
Ok, hier ein Codeschnippsel, wie ich meine Liste befülle. Mit groß meine ich so ca. 500 MB.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
List<string> testarr = new List<string>();
StreamReader sr_extrakt = new StreamReader(path);
while (sr_extrakt.Peek() >= 0)
{
  string line_out = sr_extrakt.ReadLine();
  testarr.Add(line_out);
}


Als Beispiel: Hab ca. 5,5 Mio Elemente in der Liste drin und das Programm belegt ca. 1.1 GB RAM.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 25.03.10 16:48 
Selbst wenn das keine Unicode-Datei ist, dürfte der Speicherverbrauch nicht viel höher als 1 GB liegen :gruebel: (/edit: :D). Von wie viel Arbeitsspeicher sprechen wir denn?
Aber da an dem Code nichts auszusetzen ist:
user profile iconerther hat folgendes geschrieben Zum zitierten Posting springen:
Wenn ich die Elemente aus der Liste haue sobald ich sie nicht emhr brauche und dann erst neue Elemente einfüge, sollte das Problem behoben sein?!
Ja. Wenn auf die String-Instanzen keine Referenz mehr besteht, können sie vom GC abgeräumt werden. Und das tut er spätestens vor einer OOM-Exception.

_________________
>λ=
erther Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Do 25.03.10 17:42 
Danke für die Diskussion!

Ich lese jetzt 500 Elemente als Block in meine Liste und entferne die nicht gebrauchten Elemente dann. Anschließend lese ich die nächsten 500 usw...

Hab mit C# (respektive der Programmierung im allgemeinen) noch nicht viel gemacht und stoße daher immer mal wieder auf teilweise Grundlagenfragen. Aber hier wird einem ja immer gut geholfen :D
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 25.03.10 17:59 
Wenn du sowieso jede Zeile einzeln behandelst, könntest du dir auch einmal IEnumerable<T> anschauen. Damit kannst du "Lazy Sequences" ermöglichen, bei denen idealerweise immer nur ein Element gleichzeitig im Speicher liegt.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
static IEnumerable<string> ReadLines(string path) // Ab 4.0: File.ReadLines
{
  using (StreamReader reader = new StreamReader(path))
    while (true) {
      string line = reader.ReadLine();
      if (line == null)
        yield break;
      yield return line;
    }
}

// Beispiel: Gesamtlänge aller Zeilen
ReadLines(path).Sum(line => line.Length);

_________________
>λ=


Zuletzt bearbeitet von Kha am Do 01.04.10 21:13, insgesamt 1-mal bearbeitet
traceurmicha
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 160
Erhaltene Danke: 9

Win XP SP2, Win 7 Pro., Ubuntu 9, Debian 5
C#, ASP.NET, MSSQL, PHP(Microsoft Visual Studio 2010 Ultimate, SharpDevelop 4, Microsoft SQL Server2008 Express, Eclipse for PHP)
BeitragVerfasst: Do 01.04.10 13:23 
Ich weiß das bestimmt gleich wieder einer meckert, aber ich würde das
ausblenden C#-Quelltext
1:
2:
while (true) {
      string line = reader.ReadLine();

nicht so schreiben!
Wenn ich mich jetzt nicht irre erstellt er dort immer wieder eine neue Variable "line", wäre es nicht besser man würde schreiben:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
string line = null;
while(true)
{
    line = reader.ReadLine();
    .
    .
    .
}

:?: :?:

_________________
Programmieren ist ein Rennen zwischen den Softwareentwicklern, die versuchen größere und bessere idiotensichere Programme zu schreiben und dem Universum, welches versucht größere und bessere Idioten zu produzieren. Zur Zeit liegt das Universum in Führung.
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Do 01.04.10 13:39 
Jepp, bekommst du ;)

Eine Variable erstellt er sowieso nicht ;) Höchstens legt er ein neues string-Objekt an.

Früher war es durchaus "wichtig" die Variable außerhalb einer Schleife zu deklarieren. Weil zur Laufzeit, wie du sagst, dann in jedem Durchlauf neuer Speicher für das Objekt allokiert wird. Mittlerweile ist es so, dass die Kompiler dies erkennen und bei der Übersetzung die Deklaration so oder so außerhalb machen.

Gruß
traceurmicha
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 160
Erhaltene Danke: 9

Win XP SP2, Win 7 Pro., Ubuntu 9, Debian 5
C#, ASP.NET, MSSQL, PHP(Microsoft Visual Studio 2010 Ultimate, SharpDevelop 4, Microsoft SQL Server2008 Express, Eclipse for PHP)
BeitragVerfasst: Do 01.04.10 13:59 
alles klar danielf, dan rewidiere ich meine Aussage hiermit :wink:

man lernt ebend nie aus :wink: :wink:

_________________
Programmieren ist ein Rennen zwischen den Softwareentwicklern, die versuchen größere und bessere idiotensichere Programme zu schreiben und dem Universum, welches versucht größere und bessere Idioten zu produzieren. Zur Zeit liegt das Universum in Führung.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 01.04.10 21:06 
user profile icontraceurmicha hat folgendes geschrieben Zum zitierten Posting springen:
wäre es nicht besser man würde schreiben
Wenn es lesbarer ist, ist es besser. Ist es das ;) ?

user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Früher war es durchaus "wichtig" die Variable außerhalb einer Schleife zu deklarieren. Weil zur Laufzeit, wie du sagst, dann in jedem Durchlauf neuer Speicher für das Objekt allokiert wird.
Was hat die Deklaration mit Objekt-Allokationen zu tun? Davon gibt es doch wohl in beiden Fällen genauso viele wie Schleifendurchgänge. Die Variable selbst benötigt natürlich Stackspeicher, aber der wird ja nicht allokiert.
Du hast wahrscheinlich eher daran gedacht :) .

Mal ganz abgesehen davon, dass wir uns hier in einem Iterator befinden, in dem Variablen sowieso keine Variablen bleiben :zwinker: ...

_________________
>λ=