Seite 1 von 1

Sind Array's in irgendeiner Art und Weise begrenzt ?

Verfasst: 05.06.2007 19:03
von Ingo Platte
Hallo zusammen,

ich muß CSV-Dateien auslesen und brauche dafür zwei Arrays.
Bei der Dimensionierung habe ich jeweils 100 Mio. eingeben.

Dabei ist mir aufgefallen das direkt beim ersten Eintrag im zweiten Array

Code: Alles auswählen

Array2(x_4)\Id     = ValQ(StringField(String, 1, ";"))
der Debugger mit einem "Invalid memory access" aussteigt.

Ich hab Tagelang nach dem Fehler gesucht, bis ich die Dimensionierung
auf 10 Mio. reduziert habe und der Code läuft "Simsalabim" ohne Probleme durch.

Komisch ist nur das ich erstens 2Gb Speicher hab und zweitens die
Fehlermeldung sofort kommt ohne das ein einziger Eintrag ins Array
geschrieben wurde. Deshalb wollte ich Fragen in wie weit Array's begrenzt sind, in der Hilfe steht leider auch nichts dazu.

Folgender angepasster Code erzeugt die Fehlermeldung (bei 10 mio. läufts):

Code: Alles auswählen

Structure Cat
    ID.q
    String.s
  EndStructure
  
  Dim Array1.cat(100000000)
  Dim Array2.cat(100000000)

  x_2 = 0
  While x_2 <> 10
 
    String.s = "1123;Weitere zeichen;kjhyxkjchykxjchykjch"
    Array1(x_2)\Id     = ValQ(StringField(String, 1, ";"))
    Array1(x_2)\String = Mid(String, FindString(String, ";", 0) + 1, Len(String))
    x_2 = 1 + x_2
  Wend
  x_2 = x_2 -1

  x_4 = 0
  While x_4 <> 10
      String.s =  "1123;Weitere zeichen;kajshdkjashdaksj"
    Array2(x_4)\Id     = ValQ(StringField(String, 1, ";"))
    Array2(x_4)\String = Mid(String, FindString(String, ";", 0) + 1, Len(String))
    x_4 = 1 + x_4
  Wend
  x_4 = x_4 -1

Verfasst: 05.06.2007 19:59
von Zaphod
Wenn du ein Array anlegst, wird speicher für jeden Eintrag alloziert, "leere" arrays gibt es also in pb nicht.

Denken wir also mal genauer nach... du hast eine Struktur die pro Eintrag 8+4 byte speicher braucht (eine doppelt genaue variable und einen 4 byte großen pointer).

Davon machst du zwei Arrays von jeweils 100 000 000 * 12 bytes, also ca 1.12 GigaByte, also allozierst du ca 2.24 Gigabyte.
Du hast 2GB zur verfügung (wenn es keine anwendungen neben deiner gäbe, aber da läuft ja auch schon windows drin.

Dazu allozierst du noch platz für ein paar arrays, die du dem Stringpointern dann zuweist.

Also was ist jetzt genau verwunderlich? Auch dein Auslagerungsspeicher ist begrenzt, den könntest du allerdings vergrößern.

Verfasst: 05.06.2007 20:48
von Kiffi
die Frage ist sowieso, warum man auf einen Schlag 100 oder 10 Mio Einträge
reservieren muss (und das auch noch mal zwei). Ist die CSV-Datei wirklich
so groß?

Mein Vorschlag: Entweder vergrößerst Du mit ReDim Deine Arrays
häppchenweise um 100 oder meinetwegen auch 1000 Elemente, wenn Du
merkst, dass Du an die Obergrenze Deiner ursprünglichen Dimensionierung
gelangst oder aber Du verwendest LinkedLists.

Falls Du Fragen diesbezüglich hast: Immer her damit! :-)

Grüße ... Kiffi

Verfasst: 06.06.2007 21:26
von Ingo Platte
Kiffi:
die Frage ist sowieso, warum man auf einen Schlag 100 oder 10 Mio Einträge
reservieren muss
Zugegeben, die Anzahl ist ein bissle hochgegriffen. die CSV-Dateien haben schon mehrere Hunderttausend Einträge (Messwerte) und die übertriebene Array-Dimensionierung hab ich einfach als Sicherheit angegeben.
Jetzt sinds nur noch 1 Mio. :wink:

Was mich aber interessieren würde, warum meckert PB nicht direkt bei der Dimensionierung des Array's sondern erst beim ersten Zugriff (hätte mir etliche Stunden Fehlersuche erspart)

Damit mir das Später nicht nochmal passiert:
Wie kann ich eine Reine Array-Dimensionierung (Speicherverbrauch) berrechen? Also ohne Inhalt

Structure
String.s = 4byte + 4byte Pionter ?
Quad.q = 8byte + 4byte Pionter ?
Byte.b = 1byte + 4byte Pionter ?
Endstructure
das ganz dann mal der Dimensionierung?


ciao Ingo

Verfasst: 06.06.2007 23:17
von Zaphod
Wenn du ein String deklarierst, dann ist das ersteinmal nur ein Zeiger. Wie groß ein Zeiger ist hängt von der Plattform ab. Auf einem 32 bit System (also einem in dem eine Speicheradresse 32 bit groß ist) sind das 4 byte. Purebasic kann derzeit ausschließlich 32bit Anwendungen erzeugen, also ist der Stringpointer wie andere pointer auch 32 bit groß.
Füllst du da einen String rein, kommt natürlich die größe des strings dazu (+terminierungszeichen). Wie groß das ist hängt vom Stringtyp ab (ASCII, UTF8, UTF16, UTF32).

Das quad bezeichnet direkt einen Speicherbereich und impliziert eine größe dadurch das der Compiler weiß, dass er für ein Quad immer 8 byte brauch.

Beim byte wird es ein bischen kompliziert... eigentlich ist die kleinste direktaddressierbare Speicherzelle auf einem 32 bit system eine 32 bit Speicherzelle. Den zugriff auf das byte bekommt man nur über einen Umweg. Ich nehme stark an, dass Purebasic bytes zusammen verwaltet, dass also ein byte wirklich nur ein byte speicher verbrauch, aber so sicher kann ich es jetzt auch nicht sagen ohne es auszuprobieren.

Dazu musst du dann natürlich beachten, dass der reale Speicherverbrauch trotzdem immer eine zahl ist, die durch 4 teilbar ist.... also 3 bytes belegen 4 bytes speicher. 4 bytes belegen 4 byte speicher. 5 bytes belegen 8 byte speicher usw... es kommt aber sowieso noch ein bischen schlimmer: Windows hat eine definierte Blockgröße beim allozieren von speicher (nicht nur windows... alle betriebsysteme), real ergeben sich dadurch also mal hier und da 8kb(oder waren es 4?) verlust, aber das ist in dem fall nicht dein problem, weil du zussammenhängenden Speicher allozierst, die reibungsverluste also 8kb pro array nicht übersteigen sollten (außer vieleicht noch durch struktur offsets... so eine struktur sollte besser auch durch 4 teilbar sein).

Also verbraucht deine beispielstruktur mit vorbehalt von reibungsverlusten lediglich 4+8+1 byte pro eintrag.


Du musst deine datei aber auch nicht komplett einlesen um sie zu bearbeiten... schau dir mal die File befehle genau an, du kannst auch selektiv auslesen.

Ich kann schwer einschätzen was du da vor hast, aber wenn du die CVS nur nach bestimmten Einträgen durchsuchen willst, dann würde ich nacheinander nur teile davon einlesen, bearbeiten, aus dem speicher werfen, nächsten teil einlesen usw.

Verfasst: 07.06.2007 09:23
von ZeHa
also allozierst du ca 2.24 Gigabyte.
Du hast 2GB zur verfügung (wenn es keine anwendungen neben deiner gäbe, aber da läuft ja auch schon windows drin.


Das dürfte aber eigentlich dennoch kein Problem darstellen, da unter Windows jedes Programm einen virtuellen Adreßraum zugewiesen bekommt (4 GByte), den es vollständig nutzen kann. Um dies zu realisieren, wird der Speicher bei Bedarf auf der Festplatte ausgelagert und je nach benötigten "Kacheln" werden dann bestimmte Teile hin- und hergetauscht.

Zumindest ist es unter XP so, aber vielleicht benutzt Ingo ja eine ältere Version?

Verfasst: 07.06.2007 12:34
von Kiffi
ich persönlich bin in einem solchen Fall ja ein Freund von LinkedLists :-)

Code: Alles auswählen

EnableExplicit

Structure Cat
  id.q
  String.s
EndStructure
 
NewList LL1.Cat()
NewList LL2.Cat()

Define.l LineCounter
Define.s String

For LineCounter = 0 To 9
  String = "1123;Weitere zeichen;kjhyxkjchykxjchykjch"
  AddElement(LL1())
  LL1()\id     = ValQ(StringField(String, 1, ";"))
  LL1()\String = Mid(String, FindString(String, ";", 0) + 1, Len(String))
Next

Debug "Anzahl Elemente: " + Str(CountList(LL1()))

For LineCounter = 0 To 9
  String = "1123;Weitere zeichen;kjhyxkjchykxjchykjch"
  AddElement(LL2())
  LL2()\id     = ValQ(StringField(String, 1, ";"))
  LL2()\String = Mid(String, FindString(String, ";", 0) + 1, Len(String))
Next

Debug "Anzahl Elemente: " + Str(CountList(LL2()))
Grüße ... Kiffi

Verfasst: 07.06.2007 13:00
von Leonhard
Du könntest statt LinkedList einfach das Array mit 0 erstellen und immer neue Elemente mit ReDim hinzufügen, wobei LinkedList konfortabler und warscheinlich schneller währe.

Verfasst: 07.06.2007 17:00
von Zaphod
Komfortabler, eventuell. Schneller vermutlich nicht.

Beim Array ergibt sich die genaue Position der Daten aus dem Array Index mit seiner Startadresse und der Strukturgröße. Bei der LinkedList muss dafür erst ein Zeiger ausgelesen und dereferenziert werden.

Auf jeden Fall verbraucht eine LinkedList pro Element 8 byte Speicher mehr (der vor- und zurückzeiger).