PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Garbage Collection in PHP


Airwolf89
20.07.2010, 20:07:44
Hallo Leute,

ich hätte da mal eine Frage. Meine ersten tiefergehenden Programmiererfahrungen habe ich mit Java gemacht bevor ich mich nun hauptsächlich mit PHP beschäftige.
Nun habe ich mir mal ein wenig um die Performance bei PHP Gedanken gemacht, da kommt man ja auch zwangsläufig an der Garbage Collection nicht vorbei.
Nun habe ich mich gefragt, kann man in PHP die Garbage Collection auch manuell aufrufen? In Java gibt es ja den befehl System.gc(); Gibt es sowas für PHP auch? Habe ein bisschen gegoogelt aber nichts gefunden.

Weiterhin habe ich mir dann mal Gedanken an einem konkreten Beispiel gemacht.
Mal angenommen ich habe eine Datei index.php welche eine oder mehrere Klassen instanziert, welche dann für sich auch wieder ein paar Klassen instanzieren. Mal angenommen ich rufe dann, z.B. durch einen Link wieder die index.php auf. Was passiert dann mit den Instanzen des vorherigen Durchlaufs? Ich meine, es existieren ja dann so gesehen immer noch Referenzen auf diese Klassen, allerdings kommt man an die ja nicht mehr ran. Werden die vom Garbage Collector entsorgt?

Wenn nicht, was könnte man tun damit diese nicht als Speicherleichen im Speicher vor sich hin vegetieren?

Danke im voraus.

cortex
20.07.2010, 20:49:19
mach dir keine gedanken um den php garbage collector; der arbeitet besser, als du / die meisten von uns das manuell hinbekommen würden. der gc wird bei neuen versionen immer wieder überarbeitet / verbessert; du musst dir keine sorgen machen, dass das thema seitens der entwickler stiefmütterlich behandelt würde.

Habe ein bisschen gegoogelt aber nichts gefunden.

warum suchst du nicht im php-handbuch?

Garbage Collection (http://www.php.net/manual/de/features.gc.php)

Weiterhin habe ich mir dann mal Gedanken an einem konkreten Beispiel gemacht [...]

derart primitive szenarien werden selbstverständlich durch die gc erfasst. php ist darauf zugeschnitten, via http - ein zustandsloses protokoll - zu funktionieren. von java kommend, musst du in dieser hinsicht zuerst einmal umdenken.

cx

Airwolf89
21.07.2010, 09:47:54
Ok, dann bin ich beruhigt =)

Das mit dem googlen war nur auf den manuellen Aufruf bezogen, weil ich da nichts gefunden habe.

Wenn das mit dem Beipsiel so klappt, wie du sagt, dann ist alles gut.

Vielen Dank.

rei
05.09.2010, 02:00:29
Also so uneingeschränkt zustimmen kann ich da nicht,
dass bei php gc Friede, Freude, Eierkuchen herrscht.

Man siehe nur 5.3 :
http://de.php.net/manual/de/features.gc.performance-considerations.php

Ein anderes Problem mit dem ArbeitsSpeicher kannst Du mit folgenden Script anzeigen lassen:
Es wird ein Array befüllt bis es den Arbeitsspeicher zerlegt;
-einmal ohne FunktionsAufruf, bzw direkt zuweisen,
-einmal mit FunktionsAufruf.

Eigentlich sollte es ja egal sein, aber mit FunktionsAufruf läuft der Speicher deutlich schneller voll und wird auch bei PHP 5.3 nicht korrekt bereinigt.

Das Script wurde getestet mit:
Apache2;
5.2.12 - apache2handler
5.2.12 - cgi-fcgi
5.3.1 - cgi-fcgi
Immer mit dem gleichen Ergebnis.
Egal ob gc_enabled(), manueller Aufruf von gc_collect_cycles() , ...

Ich komm bei 64MB
auf ca. 230000 Einträge ohne FunktionsAufruf
und ca. 150000 Einträge mit FunktionsAufruf
(.. und das sind leider zuwenig Einträge,
bzw berechnet mal die StringGrösse mit dem calc!)

Bitte berichtet mit Eure Erfahrungen mit dem Script und dem Arbeitsspeicher.
Merci.



<pre>
//teste wie gross ein Array werden darf bis der Arbeitssepeicher voll ist
http://de.php.net/manual/de/features.gc.php
gc_collect_cycles(); http://de.php.net/manual/de/function.gc-enabled.php
</pre>
<?php
echo "phpversion()=".phpversion()."<br>";
echo "php_sapi_name()=".php_sapi_name()."<br>";
if(function_exists('gc_enabled')){
echo "gc_enabled()=".intval(gc_enabled())."<br>";
}else{
echo "NO function: gc_enabled()<br>";
}

//print Menu BEGIN
echo '
<a href="./'.basename($_SERVER['SCRIPT_NAME']).'?mitFunktion=0" target="_self">ohne FunktionsAufruf</a><br>
<a href="./'.basename($_SERVER['SCRIPT_NAME']).'?mitFunktion=1" target="_self">mit FunktionsAufruf</a><br>
'.date('c').'<br>
';
//print Menu END

//check USER-Parameter BEGIN
$mitFunktion = false;
if(array_key_exists('mitFunktion',$_GET)){
$mitFunktion = intval($_GET['mitFunktion']);
}
//check USER-Parameter END

if($mitFunktion == false){
//run test ohne FunktionsAufruf BEGIN
$list = array();//init $list (poor old friend will hang in memory)
$key = 0;
while(true){ // = bis zum bitteren Ende
if( ($key % 10000) == 0 ){
echo "\n<br>do add 10000. count=".count($list);
}
$list[] = md5(microtime());$key++; //add simple/short String per ROW
}
//run test ohne FunktionsAufruf END
}else{
//run test MIT FunktionsAufruf BEGIN
$list = array();//init $list (poor old friend will hang in memory)
while(true){ // = bis zum bitteren Ende
$list = addRows($list, 10000);
}
//run test MIT FunktionsAufruf END
}

function addRows($list = array(), $anzahl = 10000){
//check Parameter BEGIN
if(is_array($list) == false){
$list = array();
}
$anzahl = intval($anzahl);
//check Parameter END
echo "\n<br>do add 10000. count=".count($list);
for($i = 0; $i<$anzahl; $i++){
$list[] = md5(microtime());//add simple/short String per ROW
}
return $list;
}

?>



Ich vermute der Speicher läuft beim call_by_value voll ;?
$list = addRows($list, 10000);

rei
05.09.2010, 02:36:43
Mal angenommen ich rufe dann, z.B. durch einen Link wieder die index.php auf. Was passiert dann mit den Instanzen des vorherigen Durchlaufs?

Das stimmt schon http ist zustandslos - konkret -
wenn das script fertig ist, wird alles in die Tonne getretten
und beim nächsten Aufruf von index.php neu angelegt -
JEDOCH NICHT deine SessionWerte ;)

z.B.: (Skript ist Freiflug)


<?php
//include_once('/path/to/class.myClass.php');
session_start();

if(isset($_SESSION['storedObj'])){
$myObj = unserialize($_SESSION['storedObj']);
}
else{
$myObj = new myClass('Hallo World');
}

echo ( $myObj->getST() );
$myObj->setST('Aber Hallo');


class myClass{
private $something = 'init';

function __construct($string = 'construct') {
$this->setST($string);
}

function __destruct() {
$_SESSION['storedObj'] = serialize($this);
}

function getST(){
return $this->something;
}

function setST($string = 'unset'){
$this->something = $string;
return true;
}
}

?>



geht auch eleganter...
Dein Reinhard Neidl.

DokuLeseHemmung
05.09.2010, 09:18:11
@rei

Also so uneingeschränkt zustimmen kann ich da nicht, dass bei php gc Friede, Freude, Eierkuchen herrscht.

Ach herrje...
Was meinst du?
Zirkuläre Referenzen? Was willst du damit?
Also nicht Praxis relevant.


Das Zeit Problem?
Es macht wenig Sinn in PHP tausende von Objekten oder hunderttausende Arrays zu erzeugen.
Also nicht Praxis relevant.


Ein PHP Script "lebt" nur vom Request bis zum Response. Und sobald diese Zeit länger als 500 msec dauert, fängt der Besucher an zu warten. Mehr als 10 Sekunden hält kein Besucher aus. Und klickt weg.
Die meisten Provider brechen Scripte nach 30 Sekunden ab. Dann ist sowieso Schluss mit Lustig. Also reden wir hier über Zeiten im Sekunden Bereich. Und da reicht die Zeit einfach nicht um so riesen Datenstrukturen auf zu bauen.

Bedenke:
Eine Java Applikation läuft Stunden, oder gar Tage durch.
Eine PHP Script in der Regel nur ein paar Dutzend Milli Sekunden.
Das ist ein ERHEBLICHER Unterschied.


---------
Ich habe ja keine Ahnung was du mit PHP anstellen willst, aber wenn du Schwachstellen in unserer geliebten Sprache unbedingt finden willst, dann findest du sie auch. Und wenn du unsere geliebte Sprache in aller Öffentlichkeit demontieren möchtest, kann kannst du das natürlich tun, aber welchen Sinn macht das?

Stelle bitte Praxis relevante Fragen!
Ein solches schon fast polemisches runter buttern mag ich nicht.

-----------

$myObj = unserialize($_SESSION['storedObj'])
Was soll das unserialize() da tun?
Unsinn!

Es macht herzlich wenig Sinn Session mit allem möglichen Gedöns zuzustopfen!
Z.B. die User_id in Session zu halten macht Sinn!
Aber die Rechte des Users haben da nichts zu suchen. Das wäre redundante Datenhaltung. Auch: Der Admin könnte diesen User nicht bannen.

cortex
05.09.2010, 10:41:03
ich habe bis dato keine negativen erlebnisse mit der garbage collection in php gemacht. möglicherweise liegt das daran, dass ich php ausschliesslich für webanwendungen nutze - quasi im sinne des erfinders. doku's ausführungen habe ich nichts hinzuzufügen; lediglich das bereits gesagte:

php ist darauf zugeschnitten, via http - ein zustandsloses protokoll - zu funktionieren. von java kommend, musst du in dieser hinsicht zuerst einmal umdenken.

zum thema sessions:

wenn das script fertig ist, wird alles in die Tonne getretten [...] JEDOCH NICHT deine SessionWerte ;)

ich sehe kein überraschungsmoment.

cx

knight1
05.09.2010, 14:17:22
...
Es macht herzlich wenig Sinn Session mit allem möglichen Gedöns zuzustopfen!
...

Da stimme ich Dir absolut zu.
ABER, hast Du dir schon einmal angesehen was z.B. PHPMyAdmin (PMA) alles in die Session reinhaut, ohne es wieder zu löschen wenn es nicht mehr gebraucht wird? Auf meinem Entwicklungssystem wächst die Session-Datei von PMA teilweise auf über 200KB an.

...
ich sehe kein überraschungsmoment.
...

Vor allem ist man für das was in der Session steht als Coder selbst verantwortlich, siehe mein Beispiel mit PMA. An dem Inhalt einer Session hat der GC nichts verloren.
Unter anderem wenn es an das Aufräumen des Verzeichnisses, wo die Sessions abgespeichert werden, und des in PHP definierten Temp-Verzeichnisses geht, erst dann greift der GC.
Was die PHP-Interne RAM-Verwaltung angeht, kann ich nichts zu sagen. Keine Ahnung ob da auch der GC für zu ständig ist oder ob es einen entsprchenden Programmcode innerhalb des Interpreters gibt.


Kai aka Knight1

rei
05.09.2010, 17:15:16
in PHP tausende von Objekten oder hunderttausende Arrays zu erzeugen.
Laß doch einfach mal das Script laufen, es wird ja nur ein array befüllt.

Im Frontend laufen natürlich nur ein paar Datensätze auf, im Backend sieht es manchmal anders aus.

Damit möglich Engpässe einer Anwendung, die erst in der Zukunft (gut gefüllte DB) passieren, schon im Vorfeld abgefangen werden können, ist es nun mal nötig die Engpässe/Schwachstellen zu ermitteln/benennen und zu beheben oder zu umschiffen.

z.B.:
Ein Anwendung läuft zwei, drei Jahre und die Statistiken, LogFiles, ExportDumps (für Offline) funktionieren auch gut, aber (leider) ist die Domain erfolgreich und die Exports, Archivierung, CronJobs fahren mitten drin an die Wand (und es wird erst nach zwei,drei Tagen bemerkt). Das ist unangenehm.

Da man(n) mal einen managed Server mal eine Server mit root-Zugang vorgesetzt bekommt,
kann man ja auch nicht immer alles einstellen/konfigurieren wie man will.

Nochmal zurück zum Script:
Wieviele Einträge schafft Euer Server (welche Konfig)?
Was fällt Euch ein mehr Datensätze in ein Array zu packen?

knight1
05.09.2010, 17:22:08
Aus meiner Sicht ist derjenige der Datenbank-Aufgaben mit solch vielen Datensätzen über ein PHP-Webfrontend abarbeiten lässt ... ähm, naja.

Sowas macht man meines erachtens besser über ein seprates C- oder Java-Programm (oder mit was für einer Datenbankfähigen Programmiersprache auch immer).


Kai aka Knight1

rei
05.09.2010, 17:26:25
Sowas macht man meines erachtens besser über ein seprates C- oder Java-Programm (oder mit was für einer Datenbankfähigen Programmiersprache auch immer).

Da man(n) mal einen managed Server ... vorgesetzt bekommt,...

Hast Du noch andere Möglichkeiten in petto? (...oder wendest Du Dich so schnell schon von PHP ab?)

knight1
05.09.2010, 17:33:42
Ich wende mich nicht von PHP ab, ich sehe es nur realistisch.
PHP ist schlicht weg nicht für solche Datenmengen wie Du sie Skizzierst konzipiert.
Das Hauptaugenmerk liegt nunmal im dynamischen generieren von Webseiten. Und dafür ist PHP, denke ich, auch im Kern designed.

Soweit ich weiß, kann man auch bei managed Servern eigene Programme ausführen.

Kai aka Knight1

cortex
06.09.2010, 09:44:10
Ein Anwendung läuft zwei, drei Jahre und die Statistiken, LogFiles, ExportDumps (für Offline) funktionieren auch gut, aber (leider) ist die Domain erfolgreich und die Exports, Archivierung, CronJobs fahren mitten drin an die Wand [...]

du kannst dich offensichtlich nicht ohne weiteres aus deiner java-denke lösen. zum wiederholten male: wenn ein php-skript abgearbeitet ist, werden sämtliche ressourcen freigegeben. ob das skript durch einen http-request oder einen cronjob angestossen wird, ist dabei nebensächlich. für ununterbrochen laufende programme ist die sprache nicht konzipiert; dazu würde mir persönlich im umfeld einer webanwendung auch kein anwendungsfall einfallen. es geht meines erachtens also nicht darum, engpässe / schwachstellen zu ermitteln / benennen und zu beheben oder zu umschiffen, sondern die charakteristik der sprache zu verstehen und entsprechend einzusetzen.

Hast Du noch andere Möglichkeiten in petto? (...oder wendest Du Dich so schnell schon von PHP ab?)

wer - dem gesagten zu trotze - gern mit dem kopf durch die wand rammelt, findet i.d.r. auch wege, nicht in timeouts und speicherlimits zu laufen. schau dir dazu MySQLDumper (http://www.mysqldumper.de/) an. hier wird das problem dadurch gelöst, dass sich das skript immer wieder selbst aufruft.

cx