Speicherproblem
Hallo,
obwohl hier ähnliches schon öfter gefragt wurde, fand ich nichts was mir
weitergeholfen hätte. Hier läuft lokal PHP 5.0.4 als Apache-Modul. Für
den Hausgebrauch habe ich mir ein sich selbst aufrufendes PHP-Skript
geschrieben, mit dessen Hilfe ich die in einer z.Z. gut 2,6 MB großen
CSV-Datei gespeicherten Angaben eines zu einer Karte gehörenden
Ortsverzeichnisses vervollständige, indem für jede Zeile einzeln ein
Formular befüllt wird. Über dem Datensatz wird dabei ein
Kartenausschnitt angezeigt, in dem bereits bearbeitete Orte farbig
markiert sind. Das ging bis vor einigen Tagen auch ganz gut, bis es die
Meldung "Allowed memory size of 8388608 bytes exhausted" gab. Bis dahin
habe ich die alte Fassung der Datei in eine Variable mit file()
eingelesen, die neue wurde zeilenweise in eine zweite Variable und diese
dann mit fputs() wieder in die Datei geschrieben. Gut da kann man eine
der Variable einsparen, macht dann nur noch 2,6 statt 5,2 MB, dachte
ich. Denkste, der Fehler ist wieder da.
Mal mit var_dump(get_defined_vars()); unmittelbar bevor der Fehler beim
einlesen der Datei eintritt nachsehen was da los ist. Von der Menge her
ist es nicht viel, zusammen (je) gut 100 Byte. Was ich mir aber nicht
erklären kann ist, wieso die Variablen insgesamt drei mal erscheinen,
d.h. drei mal rekursiv das gleiche array(27) { ["GLOBALS"] => ... }
erscheint. Was bedeutet die dritte Ebene ["GLOBALS"]=> *RECURSION*?
Tritt das nur bei der Ausgabe auf oder ist das während der Abarbeitung
auch so?
array(27) {
["GLOBALS"]=> &array(27) {
["GLOBALS"]=> &array(27) {
["GLOBALS"]=> *RECURSION*
["_POST"]=> array(0) {
}
["_GET"]=> array(20) {
...
Selbst wenn ich das var_dump ganz nach oben setze sieht das sinngemäß
aus. Aber eigentlich reichen drei dieser Arrays bei weitem nicht, um die
8 MB zu belegen. Wie kann man feststellen wodurch da der Speicher
verbraten wird?
Unten ist der Anfang des Skripts. Der Fehler tritt in der letzten Zeile
ein, wenn geänderte Daten gesichert werden sollen.
Gruß
Steffen
<?php
ini_set("display_errors", 1);
ini_set("error_reporting", E_ALL & ~E_NOTICE);
define("cMaxX", 25);
define("cMaxY", 23);
define("cFile", "daten.csv");
$Sel = $_GET["sl"]; # Funktionsauswahl w: schreiben, n: Neustart, z:
zum vorherigen bzw. nächsten, f: Filter setzen
$RecHex = $_GET["hex"]; # lfd Nr hex
$RecOrt = $_GET["ort"]; # Ort 1908
$RecKrs = $_GET["krs"]; # Kreis 1908
$RecLnd = $_GET["lnd"]; # Land 1908
$RecLdh = $_GET["ldh"]; # Länderkürzel heute
$RecOrh = $_GET["orh"]; # Ort heute
$RecBlt = $_GET["blt"]; # Kartenblatt
$RecX = $_GET["x"];
$RecY = $_GET["y"];
$FtOrt = $_GET["for"]; # Filter Ort 1908
$FtKrs = $_GET["fkr"]; # Filter Kreis 1908
$FtLnd = $_GET["fln"]; # Filter Land 1908
$FtLdh = $_GET["flh"]; # Filter Länderkürzel heute
$FtOrh = $_GET["foh"]; # Filter Ort heute
$FtBlt = $_GET["fbl"]; # Filter Blattnummer
$FtX = $_GET["fx"]; # Filter X = 0
function Bildbearbeiten($name, $xi, $yi, $w) {
$color = 16711680; # rot = FF0000
$img = ImageCreateFromJpeg($name . ".jpg");
for ($i = 1; $i < 10; $i++) ImageEllipse($img, $xi, $yi, $i, $i, $color);
if ($w) {
for ($i = 20; $i < 25; $i++) ImageEllipse($img, $xi, $yi, $i, $i, $color);
};
ImageJpeg($img, $name . ".jpg", 95);
ImageDestroy($img);
};
function Bildholen($Blt, $ImgNr, $X, $Y, $S, $w) {
$circle = 35;
$X += 150; $Y += 150;
$ImgT = ' width="150" height="150" border="0" alt="">';
$Ya = floor ($ImgNr / 100);
$Xa = ($ImgNr - $Ya * 100) * 150;
$Ya *= 150;
if ($ImgNr < 1000) $ImgNr = "0" . $ImgNr;
if ($X + $circle > $Xa and $X - $circle < $Xa + 150 and $Y $circle >
$Ya and $Y - $circle < $Ya + 150) {
$Xi = $X - $Xa;
$Yi = $Y - $Ya;
if ($S == "a") {
print "<img
src=\"img.php?img=$Blt/$ImgNr&cir=$circle&xi=$Xi&yi=$Yi\"$Im gT";
} else {
Bildbearbeiten("$Blt/$ImgNr", $Xi, $Yi, $w);
};
} elseif ($S == "a") {
print "<img src=\"$Blt/$ImgNr.jpg\"$ImgT";
};
};
setlocale (LC_COLLATE, "pl_PL" );
if ($Sel == "n") {
$FtX = "0";
} elseif ($Sel == "w") { # Farbmarkierung des Ortes
$RecXt = floor($RecX / 150);
$RecYt = floor($RecY / 150);
if ($RecXt * 150 > $RecX - 75) $RecXt -= 1;
if ($RecYt * 150 > $RecY - 75) $RecYt -= 1;
$RecXt -= 1;
if ($RecXt < 1) $RecXt = 1; if ($RecXt > cMaxX) $RecXt = cMaxX;
if ($RecYt < 1) $RecYt = 1; if ($RecYt > cMaxY) $RecYt = cMaxY;
$LnkNr = $RecYt * 100 + $RecXt;
for ($Y = 0; $Y < 400; $Y += 100) {
for ($X = 0; $X < 6; $X++) {
Bildholen($RecBlt, $LnkNr + $X + $Y, $RecX, $RecY, "w",
(strtolower($RecLdh) == strtolower($FtLdh)));
};
};
var_dump(get_defined_vars());
$dtin = file(cFile);
--
Schluß mit der Rechtschreibdeform!
Warum? -> http://www.heide-kuhlmann.de/ma_frame.html (nicht meine Seite)
Alte Signal- u. Stellwerkstechnik: http://www.blocksignal.de/
bcc gehen ungelesen nach /dev/tonne
Re: Speicherproblem
Steffen Buhr schrieb:
> obwohl hier ähnliches schon öfter gefragt wurde, fand ich nichts was mir
> weitergeholfen hätte. Hier läuft lokal PHP 5.0.4 als Apache-Modul. Für
> den Hausgebrauch habe ich mir ein sich selbst aufrufendes PHP-Skript
> geschrieben, mit dessen Hilfe ich die in einer z.Z. gut 2,6 MB großen
> CSV-Datei gespeicherten Angaben eines zu einer Karte gehörenden
> Ortsverzeichnisses vervollständige, indem für jede Zeile einzeln ein
> Formular befüllt wird. Über dem Datensatz wird dabei ein
> Kartenausschnitt angezeigt, in dem bereits bearbeitete Orte farbig
> markiert sind. Das ging bis vor einigen Tagen auch ganz gut, bis es die
> Meldung "Allowed memory size of 8388608 bytes exhausted" gab. Bis dahin
> habe ich die alte Fassung der Datei in eine Variable mit file()
> eingelesen, die neue wurde zeilenweise in eine zweite Variable und diese
> dann mit fputs() wieder in die Datei geschrieben. Gut da kann man eine
> der Variable einsparen, macht dann nur noch 2,6 statt 5,2 MB, dachte
> ich. Denkste, der Fehler ist wieder da.
Die Datei passt in den Speicher, das Bild aber wahrscheinlich nicht. Wie
groß (Dimension) sind die Karten, die du mit deinem Script bearbeitest?
> Mal mit var_dump(get_defined_vars()); unmittelbar bevor der Fehler beim
> einlesen der Datei eintritt nachsehen was da los ist. Von der Menge her
> ist es nicht viel, zusammen (je) gut 100 Byte.
Das sagt gar nichts aus. Selbst ein NULL-Pointer belegt knapp 70 Byte
Speicher für nichts. Auf der anderen Seite sollte "Reference Counting"
wiederum etwas Platz einsparen.
var_dump() ist nicht das optimale Mittel um den Speicherverbrauch zu
messen. Verwende dazu lieber memory_get_usage() oder
memory_get_peak_usage() bzw. einen Debugger.
> Was ich mir aber nicht
> erklären kann ist, wieso die Variablen insgesamt drei mal erscheinen,
> d.h. drei mal rekursiv das gleiche array(27) { ["GLOBALS"] => ... }
> erscheint. Was bedeutet die dritte Ebene ["GLOBALS"]=> *RECURSION*?
Ab der dritten Ebene wird nichts mehr ausgegeben, weil dein Script sonst
nie mehr mit der Ausgabe aufhören würde das GLOBALS-Array auszugeben,
Rekursion halt.
> Tritt das nur bei der Ausgabe auf oder ist das während der Abarbeitung
> auch so?
Ich hab das gerade mal ausprobiert und bei folgendem Code kriege ich
einen "Segmentation Fault", also einen Speicherzugriffsfehler. Damit
hätte ich nicht gerechnet.
<?php
function recursion($var) {
foreach($var as $k => $v) {
if(is_array($v)) {
return recursion($v);
}
print "$k => $v\n";
}
}
recursion($GLOBALS);
?>
Das hat mit deinem Problem aber nichts zutun, denn das bedeutet
natürlich nicht, dass die Variable unendlich oft im Speicher ist. Es
handelt sich dabei nur um eine Referenz, da $GLOBALS ja eine globale
Variable ist, die im $GLOBALS-Array wieder auftauchen, muss ... etc.
> array(27) {
> ["GLOBALS"]=> &array(27) {
> ["GLOBALS"]=> &array(27) {
> ["GLOBALS"]=> *RECURSION*
> ["_POST"]=> array(0) {
> }
> ["_GET"]=> array(20) {
> ...
> Selbst wenn ich das var_dump ganz nach oben setze sieht das sinngemäß
> aus. Aber eigentlich reichen drei dieser Arrays bei weitem nicht, um die
> 8 MB zu belegen. Wie kann man feststellen wodurch da der Speicher
> verbraten wird?
Mit memory_get_usage() oder memory_get_peak_usage().
> Unten ist der Anfang des Skripts. Der Fehler tritt in der letzten Zeile
> ein, wenn geänderte Daten gesichert werden sollen.
Die letzte Zeile deines Codes ist eine Leerzeile und die letzte Zeile
mit Code sichert nichts, sondern liest die Datei in $dtin. Schreib das
nächste mal die genaue Fehlermeldung mit Zeilenangabe, deinen Code hab
ich nur überflogen.
MfG,
Thomas
Re: Speicherproblem
Steffen Buhr schrieb:
> obwohl hier ähnliches schon öfter gefragt wurde, fand ich nichts wa=
s mir
> weitergeholfen hätte. Hier läuft lokal PHP 5.0.4 als Apache-Modul. =
Für
> den Hausgebrauch habe ich mir ein sich selbst aufrufendes PHP-Skript
> geschrieben, mit dessen Hilfe ich die in einer z.Z. gut 2,6 MB großen=
> CSV-Datei gespeicherten Angaben eines zu einer Karte gehörenden
> Ortsverzeichnisses vervollständige, indem für jede Zeile einzeln ei=
n
> Formular befüllt wird. =DCber dem Datensatz wird dabei ein
> Kartenausschnitt angezeigt, in dem bereits bearbeitete Orte farbig
> markiert sind. Das ging bis vor einigen Tagen auch ganz gut, bis es die=
> Meldung "Allowed memory size of 8388608 bytes exhausted" gab.
Dann erhöhe doch einfach erstmal das memory_limit...
Bedenke bitte auch, dass PHP bis zur Version 5.2 keine exakten Aussagen
zum Speicherverbrauch treffen kann. Da gehören mal die Speicherbereiche=
externer Module (Bild im Speicher, wenn es von libgd rotiert wird) dazu
und mal nicht. Verlässlich sind die Speicherverbrauchsangaben laut den
Devs erst in Version 5.2 geworden und da hat man auch gleich mal den
Standardwert für memory_limit auf 128MB erhöht, weil ein ganzer Batze=
n
an Applikationen bei korrekter Messung die zuvor gültige Vorgabe von 8M=
B
überschreitet.
OLLi
--
"Herr, wir danken dir für die Speisen, die du uns beschert hast. Behü=
te
die, die nicht bei uns sein können, auch unsere Landsleute, die uns in
einem fernen Land in einem Krieg beschützen, der uns durch die Lügen =
der
Regierung aufgezwungen worden ist."
[Tischgebet, ER 1205]
Re: Speicherproblem
Thomas Hamacher meinte:
> Die Datei passt in den Speicher, das Bild aber wahrscheinlich nicht. Wie
> groß (Dimension) sind die Karten, die du mit deinem Script bearbeitest?
Die Kartenblätter sind in 150 x 150 Pixel große Bildteile zerlegt, von
denen im ungünstigsten Fall vier nacheinander bei der Markierung eines
Ortes angefaßt werden müssen. Die Markierung besteht aus einem roten
Punkt mit 9 Pixeln Durchmesser. Es wird auch stets ImageDestroy()
benutzt, so daß der belegte Speicher eigentlich wieder freigegeben sein
sollte.
> var_dump() ist nicht das optimale Mittel um den Speicherverbrauch zu
> messen. Verwende dazu lieber memory_get_usage() oder
Bringt unmittelbar vor dem Fehlereintritt 181720, also fast nichts.
> memory_get_peak_usage() bzw. einen Debugger.
Das ergibt "Call to undefined function" und im PHP-Manual steht nicht
ab welcher Version es memory_get_peak_usage() gibt. Mit debuggen bei PHP
kenne ich mich nicht aus. Ich hätte wohl gleich noch schreiben sollen,
daß ich ziemlicher Anfänger bin, der immer nur gerade das heraussucht,
was für die angestrebte Lösung nützlich scheint.
>> Unten ist der Anfang des Skripts. Der Fehler tritt in der letzten Zeile
>> ein, wenn geänderte Daten gesichert werden sollen.
>
> Die letzte Zeile deines Codes ist eine Leerzeile und die letzte Zeile
> mit Code sichert nichts, sondern liest die Datei in $dtin. Schreib das
Schon klar, hab ich nicht sauber formuliert. Die Datei soll in der Zeile
zum anschließenden ändern und schreiben eingelesen werden. Aber nicht
bei jedem Aufruf des Skriptes muß etwas geschrieben werden.
> nächste mal die genaue Fehlermeldung mit Zeilenangabe, deinen Code hab
> ich nur überflogen.
Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to
allocate 16 bytes) in /srv/www/htdocs/krt/d08/koordinaten.php on line 77
Zeile 77 ist die, in der die Datei eingelesen wird.
Gruß
Steffen
--
Schluß mit der Rechtschreibdeform!
Warum? -> http://www.heide-kuhlmann.de/ma_frame.html (nicht meine Seite)
Alte Signal- u. Stellwerkstechnik: http://www.blocksignal.de/
bcc gehen ungelesen nach /dev/tonne
Re: Speicherproblem
Oliver Grätz meinte:
> Dann erhöhe doch einfach erstmal das memory_limit...
Ja, das hatte ich nach entsprechenden Tips zu ähnlichen Fragen auch
schon in Betracht gezogen, scheint mir aber doch etwas unsportlich ;-)
weil ich den Fehler nicht plausibel finde.
> Devs erst in Version 5.2 geworden und da hat man auch gleich mal den
> Standardwert für memory_limit auf 128MB erhöht, weil ein ganzer Batzen
> an Applikationen bei korrekter Messung die zuvor gültige Vorgabe von 8MB
> überschreitet.
Sieh da, interessant.
Gruß
Steffen
--
Schluß mit der Rechtschreibdeform!
Warum? -> http://www.heide-kuhlmann.de/ma_frame.html (nicht meine Seite)
Alte Signal- u. Stellwerkstechnik: http://www.blocksignal.de/
bcc gehen ungelesen nach /dev/tonne
Re: Speicherproblem
Steffen Buhr schrieb:
> Thomas Hamacher meinte:
>> memory_get_peak_usage() bzw. einen Debugger.
>
> Das ergibt "Call to undefined function" und im PHP-Manual steht nicht
> ab welcher Version es memory_get_peak_usage() gibt.
http://de.php.net/memory_get_peak_usage:
"(PHP 5 >= 5.2.0)"
Gruß
JPM
Re: Speicherproblem
Jens Peter Moeller meinte:
> Steffen Buhr schrieb:
>> Das ergibt "Call to undefined function" und im PHP-Manual steht nicht
>> ab welcher Version es memory_get_peak_usage() gibt.
>
> http://de.php.net/memory_get_peak_usage:
> "(PHP 5 >= 5.2.0)"
Da werde ich mir wohl mal eine neue Ausgabe des Handbuchs ziehen ...
Gruß
Steffen
--
Schluß mit der Rechtschreibdeform!
Warum? -> http://www.heide-kuhlmann.de/ma_frame.html (nicht meine Seite)
Alte Signal- u. Stellwerkstechnik: http://www.blocksignal.de/
bcc gehen ungelesen nach /dev/tonne