PHP Speicherverwaltung & Garbage Collector einfach erklärt

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum sollten wir uns überhaupt um den Speicher in PHP kümmern?

\n

Die meisten PHP-Entwickler behandeln Speicher wie eine unendliche Ressource. Ein Array mit einer Million Elementen anlegen? Kein Problem. Ein Objekt erstellt und dann vergessen? Auch egal, PHP räumt schon selbst auf. Doch wenn dein Projekt plötzlich mit der Fehlermeldung Allowed memory size exhausted abstürzt oder ohne ersichtlichen Grund langsamer wird, ist es Zeit, einen Blick unter die Haube zu werfen.

\n

Heute tauchen wir in die Blackbox namens „Speicherverwaltung und Garbage Collector in PHP“ ein. Du erfährst, wie PHP Referenzen zählt, warum zyklische Referenzen problematisch sind und wie du den Garbage Collector zu deinem Vorteil nutzt. Los geht's!

\n\n

Wie PHP den Speicher verwaltet: Von der Anfrage bis zur Antwort

\n

Anders als in C oder C++, wo du Speicher selbst reservieren und freigeben musst, arbeitet PHP über die Zend Engine. Jeder PHP-Prozess hat seinen eigenen Speicherpool. Wenn du schreibst:

\n
$data = [1, 2, 3];
\n

reserviert PHP Speicher für das Array, speichert die Werte und erhöht den sogenannten refcount (Referenzzähler). Solange jemand auf die Variable $data verweist, wird der Speicher nicht freigegeben.

\n

Sobald du jedoch Folgendes ausführst:

\n
unset($data);
\n

fällt der Referenzzähler auf null, und die Zend Engine gibt den Speicher sofort wieder in den Pool zurück. Einfach und schnell. Aber es gibt Feinheiten…

\n\n

Referenzarithmetik: refcount und is_ref

\n

Jede Variable in PHP ist eine zval-Struktur, die den Wert, den Typ, das Flag is_ref (ob es eine Referenz ist) und den refcount speichert. Schauen wir uns ein Beispiel an:

\n
$a = "Hallo";\n$b = $a;  // refcount erhöht sich auf 2 (Copy-on-Write)\n$b = "Welt"; // jetzt sind $a und $b unterschiedliche zvals, refcount für "Hallo" fällt auf 1\n
\n

Das nennt man Copy-on-Write. Solange du den Wert nicht änderst, spart PHP Speicher, indem es denselben Bereich nutzt. Sobald du die Variable jedoch änderst, wird eine Kopie erstellt. Raffiniert, oder?

\n\n

Der Garbage Collector (GC): Wenn refcount nicht ausreicht

\n

Der normale Referenzzähler-Mechanismus funktioniert in 99 % der Fälle einwandfrei. Aber es gibt ein Problem – zyklische Referenzen. Stell dir vor, du hast zwei Objekte, die aufeinander verweisen:

\n
class Node {\n    public $next;\n}\n\n$a = new Node();\n$b = new Node();\n$a->next = $b;\n$b->next = $a;\n\nunset($a);\nunset($b);\n
\n

Nach unset haben beide Objekte immer noch einen refcount von 1 (jedes verweist auf das andere). Formal sind sie aus dem Code nicht mehr erreichbar, aber der Speicher wird nicht freigegeben. Das ist eine zyklische Referenz.

\n

Wenn es viele solcher Objekte gibt, entsteht ein Speicherleck. Um dem entgegenzuwirken, wurde in PHP ab Version 5.3 ein vollwertiger Garbage Collector (GC) eingeführt.

\n\n

Wie funktioniert der GC in PHP?

\n

Der Garbage Collector wird nicht bei jeder Codezeile ausgeführt. Er wird aktiviert, wenn der Root-Puffer (ein Array potenzieller zyklischer Referenzen) voll ist. Standardmäßig hat er eine Größe von 10.000 Elementen. Wenn der Puffer voll ist, startet der GC einen Algorithmus, der:

\n
    \n
  • Roots scannt – findet alle zvals mit refcount > 0, die Teil eines Zyklus sein könnten.
  • \n
  • refcount reduziert – für alle untergeordneten Elemente (als ob es keine Referenzen gäbe).
  • \n
  • Prüft – ob der refcount nach der Reduzierung null ist; dann handelt es sich um „Müll“, der gelöscht werden kann.
  • \n
  • Stellt refcount wieder her – für diejenigen, die kein Müll sind, und gibt den Speicher frei.
  • \n
\n

Dieser Prozess heißt Garbage Collection. Du kannst ihn manuell auslösen:

\n
gc_collect_cycles();
\n

Aber tu das nicht bei jeder Kleinigkeit – es ist eine teure Operation.

\n\n

Wie erkennt man Speicherlecks in PHP?

\n

Wenn dein Skript lange läuft (z. B. ein Queue-Worker oder ein Daemon), werden Speicherlecks kritisch. Hier sind einige Werkzeuge und Techniken, um sie zu identifizieren:

\n
    \n
  • memory_get_usage() – Zeigt den aktuellen Speicherverbrauch an.
  • \n
  • memory_get_peak_usage() – Zeigt den maximalen Speicherverbrauch während der Ausführung.
  • \n
  • gc_status() – Gibt Informationen über den aktuellen Status des Garbage Collectors aus (seit PHP 7.3).
  • \n
  • Xdebug – Erweiterte Debugging-Tools zur Speicheranalyse.
  • \n
\n

Ein typisches Anzeichen für ein Speicherleck ist, wenn der Speicherverbrauch eines Skripts kontinuierlich ansteigt, ohne jemals wieder zu fallen. In solchen Fällen hilft oft ein manueller Aufruf von gc_collect_cycles() an strategischen Stellen.

\n\n

Praktische Tipps zur Speicheroptimierung in PHP

\n

Hier sind einige bewährte Methoden, um Speicherprobleme in PHP zu vermeiden:

\n
    \n
  • Unset große Variablen frühzeitig – Wenn du ein großes Array oder Objekt nicht mehr brauchst, gib es mit unset() frei.
  • \n
  • Vermeide zyklische Referenzen – Überlege genau, ob Objekte wirklich aufeinander verweisen müssen. Oft reichen schwache Referenzen oder eine andere Architektur.
  • \n
  • Nutze Generatoren – Statt ein großes Array auf einmal zu erstellen, verwende yield, um Daten in kleinen Häppchen zu verarbeiten.
  • \n
  • Batch-Verarbeitung – Bei der Verarbeitung großer Datenmengen (z. B. aus einer Datenbank) verarbeite sie in Batches und setze die Variablen nach jedem Batch zurück.
  • \n
  • GC deaktivieren (nur in Ausnahmefällen) – In langlaufenden Skripten kannst du den GC temporär deaktivieren (gc_disable()) und nur an bestimmten Punkten manuell auslösen.
  • \n
\n

Mit diesen Techniken kannst du die Speichernutzung deiner PHP-Anwendungen deutlich verbessern und unerwartete Abstürze vermeiden.

Blogs

Buchempfehlungen