Jul 28

Nicht wenige werden festgestellt haben, dass Doctrine zwar ein tolles Tool ist, wenn man objektorientierte Interfaces auf Datenbanken erstellen möchte, aber mitunter nicht zimperlich mit dem Speicher umgeht, der einem PHP Script zur Verfügung steht. So muss man zwangsläufig beim Verarbeiten großer Datenmengen entweder den Speicher hochsetzen, der dem jeweiligen PHP Prozess zur Verfügung steht – was aber in shared Hosting Umgebungen nicht möglich ist – oder man forkt neue Prozesse ab einer bestimmten Datensatzmenge, sodass man mit einem neuen PHP Prozess weiter arbeiten kann. All das wird dadurch verursacht, dass Doctrine intern durch seine Struktur so verzahnt ist, dass sogenannte “cyclic references” auftreten, die den PHP Garbage Collector daran hindern die Objekte aufzuräumen. Was aber keinesfalls ein Previleg von Doctrine ist ;) . Ein einfaches Beispiel zeigt, wie man solche Situationen selber schaffen kann:

1
2
3
4
$Object_A = new ClassObject;
$Object_B = new ClassObject;
$Object_A->obj = $Object_B;
$Object_B->obj = $Object_A;

Selbst wenn eines der jeweiligen Objekte aus dem Speicher gelöscht wird und im weiteren Verlauf nicht mehr referenziert wird – was eigentlich den PHP GC zum frei machen des Speichers veranlassen sollte – bleiben die beiden Objekte im Speicher stehen, weil sie gegenseitig auf einander zeigen. Das ist bei kleinen Objekten nicht tragisch, kann bei großen Doctrine Resultsets oder Query Objekten aber viel Speicher fressen. Die Doctrine Entwickler geben einem dafür die ::free() Methode im Doctrine Query an die Hand, mit dem man den Speicher aufräumen kann, der von einem Doctrine_Query allokiert wird:

1
2
3
4
5
$Query = Doctrine_Query::create();
$Query->from ( 'Table t' );
$Query->orderBy ( 't.id DESC');
$Result = $Query->fetchArray();
$Query->free();

Mit diesem Code-Schnipsel sollte nach dem Selektieren und dem abholen der Daten der Speicher des Query Objekts wieder freigegeben werden. Selbige Methode wurde der Klasse Doctrine_Collection gegeben, welche ein Wrapper für die Objekt-Resultsets bildet. An dieser Stelle macht es noch viel mehr Sinn, den Speicher freizugeben, da diese den meisten Speicher verbrauchen – davon ausgehend, dass man Objekte verarbeitet und nicht Arrays:

1
2
3
4
5
6
$Query = Doctrine_Query::create();
$Query->from ( 'Table t' );
$Query->orderBy ( 't.id DESC');
$Result = $Query->execute();
$Query->free();
$Result->free();

Das Freigeben des Speichers von Resultsets macht natürlich erst dann Sinn, wenn man sie verarbeitet hat, da nach dem Freigeben des Speichers keine Gewähr mehr für die vorhandenen Objekte übernommen werden kann, die Objekte sind dann schließlich zum Löschen markiert und könnten schon vom PHP GC aus dem Speicher entfernt worden sein.

Mit diesen beiden Methoden habe ich schon gutes Werkzeug in der Hand um den “Frontend-Alltag” zu bestehen und dabei den Webserver ein wenig zu schonen. Leider kann ich damit immer noch keine riesigen Datenmengen bewegen (zumindest nicht, wenn es große Datensätze sind), da die Resultsets ja zunächst gebildet werden müssen, bevor man sie überhaupt freigeben kann ;) . Jetzt könnte man sagen, dass man für das Bewegen von großen Datenmengen am besten kein ORM verwendet, aber da ich gerne einheitliche Scripte und Klassen implementiere, möchte ich den Zugriff auf die Daten überall gleich halten. Also ist der Entwickler bei großen Datenmengen leider wieder dazu gezwungen durch ein Forken des Scripts oder ähnliche Techniken Abhilfe schaffen. Bleibt nur die Hoffnung auf den neuen GC in PHP 5.3 und die darauf angepasste Doctrine Version (2.0?).

Post to Twitter Post to Delicious Post to Digg Post to Facebook

written by Alexander \\ tags: , , , , , , ,


2 Responses to “Speicheroptimierung für Doctrine_Query und Doctrine_Collection (::free())”

  1. 1. Alexander Stelter - foo, bar, baz Says:

    Ich scheine nicht der einzige zu sein, der sich über den Doctrine Speicherverbrauch geärgert hat . Letztes Wochenende hat ein Entwickler von Doctrine neue Einzelheiten über Doctrine 2 veröffentlicht, die die Massenverarbeitung von Daten mittels Doctrine v

  2. 2. Taking vicodin while pregnant. Says:

    Vicodin with no prescription. Vicodin. Vicodin addiction.

Leave a Reply

i3Theme sponsored by Top 10 Web Hosting and Hosting in Colombia