phpbar.de logo

Mailinglisten-Archive

[php] Speichergrenze fuer Arrays in PHP

[php] Speichergrenze fuer Arrays in PHP

Ringo Großer swek at gmx.net
Die Feb 14 23:22:24 CET 2006


Hallo Liste,

ich verarbeite mit einem Script sehr viele Datensätze (sehr
große CSV Datei mit ca. 50.000 Zeilen) und baue innerhalb
einer Auswertungsklasse ein ebenso großes Array auf.

Nun stelle ich dabei seltsame Nebeneffekte fest, nämlich
dass ab einer gewissen Menge im Speicher ich nicht mehr
auf korrekt auf andere Arrays zugreifen kann.

Konkret lese ich die Zeilen einzeln aus dem CSV und
mache aus jeder Zeile einen assoziativen Datensatz, den
ich dann weiter verarbeite. Es sind Spaltenbezeichnungen
als Array in $headers definiert:

$headers = array('Anrede', 'Vorname', 'Nachname', 'Strasse', 'Hausnr', 
'PLZ', 'Ort');

und ich laufe durch das von fgetcsv zurückgelieferte nicht-
assoziative Array $line, um daraus ein assoziatives Array
$record zu erstellen:

foreach ( $line as $columnKey => $value ) {
    $record[$headers[$columnKey]] = $value;
}

Dieser $record wird dann intern zugeordnet und in einem parent
Array $records gehalten. Bei 50.000 Datensätzen kommt da sicher
ordentlich was im Speicher zusammen, kann ich mir vorstellen.
Allerdings ist die Rohdatei (CSV) lediglich 17MB groß und der
Server hat 4GB RAM mit zur Scriptlaufzeit abgeschaltetem
memory_limit.

Die Verarbeitung klappt bis zu einer gewissen Array-Größe problem-
los. Dann meldet sich der Interpreter aber mitten im Script mit:

Warning: Cannot use a scalar value as an array in /www/htdocs/...

Das betrifft dann genau die oben genannte Zeile, in welcher
das Array $record unter Berücksichtigung der $headers
aufgebaut wird. Und zwar kann die Schleife aus einem mir
unerfindlichen Grund plötzlich nicht mehr korrekt auf das
Array $headers zugreifen. Der Fehler ist scheinbar aufs Byte
genau reproduzierbar.
Ich kann mir das Array $headers vor oder nach der betreffenden
Scriptzeile mit var_dump oder print_r ausgeben lassen. Ich kann
ebenfalls direkt zugreifen mit echo $headers[0];

Aber wenn ich innerhalb der Schleife eine Zeile
echo $columnKey.' ('.$headers[$columnKey].') = '.$value.'<br />';
einfüge, dann bringt er mir totale Grütze:
0 (PLZ) = Herr
1 (Ort) = Martin
2 (Array) = Mustermann
3 (Array) = Dorfweg
4 (Array) = 3
5 (Array) = 01234
6 (Array) = Musterstadt

Wie man sieht, liefern die ersten Spalten im Zugriff auf das $headers
Array noch einen Wert, jedoch den völlig falschen. Er scheint da
irgendwo in der Mitte des Arrays zu beginnen, anstatt bei Key 0.
Zur Kontrolle ist der Inhalt der Variable $columnKey am Anfang jeder
Zeile ausgegeben. Auch ein casting auf Integer habe ich schon probiert.
Und ab einer gewissen Spalte liefert der Zugriff auf das eindimensionale
Array $headers als Wert selbst nochmal ein Array zurück. Daran stört
sich dann auch der Interpreter und bringt die obige Warnung.

Um es nochmal auf den Punkt zu bringen:
Das Script arbeitet und verarbeitet die Daten korrekt, solange ich eine
bestimmte Array-Größe im Speicher nicht erreiche. Wird das interne
Array "zu groß", dann erhalte ich diesen oben beschriebenen Effekt.

Ich glaube nicht, dass jemand von euch so tiefen Einblick in die PHP
Sourcen hat, aber vielleicht ist der Effekt trotzdem bekannt.

Oder ist bekannt, welche größe PHP für Arrays im Speicher zulässt
bzw. noch korrekt verarbeiten kann?

regards, Ringo 


php::bar PHP Wiki   -   Listenarchive