Kurz gesagt: Ein PHP-Out-of-Memory-Fehler entsteht, wenn ein Skript mehr Speicher anfordern will, als die Einstellung memory_limit erlaubt (Standard: 128 MB je Anfrage). PHP bricht die Anfrage dann mit einem fatalen Fehler ab und räumt auf. Genau dieser Abbruch- und Aufräumweg war bei CVE-2026-109618, einer der beiden PHP2Shell-Lücken, fehlerhaft. Seit PHP 8.5.12, 8.4.27, 8.3.36 und 8.2.35 ist memory_limit eine weiche Grenze, ergänzt um die harte Grenze memory_hard_limit_percent.
Was bedeutet „Allowed memory size exhausted“?
Die bekannte Fehlermeldung lautet sinngemäß: „Allowed memory size of 134217728 bytes exhausted (tried to allocate …)“. Die erste Zahl ist das eingestellte Limit in Bytes, hier 128 MB. Ein Skript hat also versucht, Speicher über diese Grenze hinaus zu belegen, etwa beim Laden einer großen Datei, einer riesigen Datenbankabfrage oder durch eine Endlosschleife.
Für Entscheider wichtig: Die Grenze gilt je PHP-Prozess und je Anfrage, nicht für den ganzen Server. Sie schützt den Server davor, dass ein einzelnes fehlerhaftes Skript allen Speicher aufbraucht. Die Gesamtlast ergibt sich erst aus der Zahl der gleichzeitig laufenden Worker. Bei 20 PHP-FPM-Workern mit je 256 MB Grenze sind das rechnerisch über 5 GB.
Wie PHP Speicher zählt
PHP verwaltet Speicher für Anfragen über einen eigenen Speichermanager, den Zend Memory Manager. Er holt größere Blöcke vom Betriebssystem und verteilt sie intern an Variablen, Arrays und Objekte. Gegen diesen reservierten Wert prüft PHP das memory_limit. Speicher, den eine Erweiterung direkt beim Betriebssystem anfordert, taucht laut Handbuch in dieser Zählung nicht auf.
Sie können die Werte im Code sichtbar machen:
<?php
echo memory_get_usage(), PHP_EOL; // aktuell vom Skript belegter Speicher
echo memory_get_usage(true), PHP_EOL; // vom Speichermanager reserviert; dagegen prüft memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL; // bisheriger Spitzenwert
unset($liste);
memory_reset_peak_usage(); // Spitzenwert zurücksetzen, ab PHP 8.2
Wie Referenzzählung und Garbage Collection den Speicher wieder freigeben, erklärt die Seite Speicherverwaltung in PHP.
Was beim Out-of-Memory im Inneren passiert
Vereinfacht läuft ein Speicherabbruch in diesen Schritten ab:
- Das Skript fordert Speicher an, zum Beispiel für ein neues Array-Element oder beim Einlesen von Anfragedaten.
- Der Speichermanager prüft, ob die Anforderung die Grenze überschreitet.
- Ist das der Fall, löst PHP einen fatalen Fehler aus und verlässt die laufende Verarbeitung sofort, auch mitten in einer halb erledigten Aufgabe.
- Registrierte Shutdown-Funktionen laufen noch; damit protokollieren viele Anwendungen den Fehler.
- Am Ende räumt PHP die Anfrage auf und gibt deren Speicher frei. Der Worker steht danach für die nächste Anfrage bereit.
Der heikle Punkt ist Schritt 5. Das Aufräumen muss mit Datenstrukturen umgehen können, die beim Abbruch erst halb angelegt waren. Ein gewöhnlicher Speicherabbruch gilt laut Sicherheitsrichtlinie des PHP-Projekts nicht als Sicherheitslücke, solange das Limit die Anforderung ablehnt und nur die aktuelle Anfrage endet. Bei CVE-2026-109618 war genau diese Annahme verletzt: Laut php.net konnte der Out-of-Memory-Zustand PHP unterbrechen, während interne Anfragedaten nur teilweise initialisiert waren, und das Aufräumen behandelte ungültige Daten dann als gültig. Details zur Ausnutzung veröffentlichen wir nicht; die Einordnung der Lücke steht unter CVE-2026-109618.
Die neue weiche und harte Speichergrenze
Mit den Sicherheitsreleases vom 21.10.2026 hat das PHP-Projekt das Verhalten geändert. Laut Handbuch ist memory_limit seitdem eine weiche Grenze: Eine Anforderung, die sie überschreitet, darf in den meisten Fällen noch abgeschlossen werden, bevor der fatale Fehler folgt. Eine separate harte Grenze begrenzt, wie weit das gehen darf.
| Direktive | Standard | Änderbar | Bedeutung |
|---|---|---|---|
memory_limit |
128M | INI_ALL | Speichergrenze je Anfrage, -1 = keine Grenze |
memory_hard_limit_percent |
nicht gesetzt | INI_ALL | Harte Grenze in Prozent von memory_limit, neu seit 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
post_max_size |
8M | INI_PERDIR | Maximale Größe der POST-Daten |
upload_max_filesize |
2M | INI_PERDIR | Maximale Größe einer hochgeladenen Datei |
Ein Beispiel aus dem Handbuch: Bei memory_limit=128M und memory_hard_limit_percent=150 liegt die harte Grenze bei 192 MB. Das Handbuch nennt die Direktive zugleich als Erkennungsmerkmal: Kennt eine PHP-Version sie nicht, ist sie von CVE-2026-109618 und CVE-2026-109619 betroffen. Ein schneller Test für jede installierte PHP-Version:
php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) bedeutet: Direktive unbekannt
Bei Paketen aus Distributionen mit Backport bleibt der Paket-Changelog der maßgebliche Nachweis, wie unter PHP-Version und Patchstand richtig prüfen beschrieben. Prüfen Sie außerdem die PHP-FPM-Binary separat, denn sie kann eine andere Version haben als die Kommandozeile.
Speichergrenzen und PHP2Shell: Was Admins jetzt beachten
Die Übergangsmaßnahmen von php.net zu CVE-2026-109618 drehen sich fast alle um Speicher und Anfragegrößen. Sie verringern das Risiko, ersetzen aber das Update nicht:
; FPM-Pool, z. B. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M ; 32M, wenn Uploads nötig sind
php_admin_value[upload_max_filesize] = 6M ; unter post_max_size halten
Drei Punkte sind dabei entscheidend. Erstens darf keine Anwendung, kein Verzeichnis und kein anderer Pool wieder eine endliche Grenze setzen; php.net verlangt ausdrücklich diese Kontrolle. Zweitens braucht ein Dienst mit memory_limit=-1 eine Grenze von außen, über Container oder cgroup, nach php.net am besten so, dass nur der betroffene Worker beendet wird. RLIMIT_AS und RLIMIT_DATA sind laut php.net ungeeignet. Drittens empfiehlt php.net Grenzen am Webserver oder Proxy für Anfragegröße, Zahl der Felder, Multipart-Teile, Header und Verschachtelungstiefe.
memory_limit=-1 ohne Speichergrenze von außen kann einen Server bei hoher Last komplett lahmlegen. Setzen Sie die Übergangsmaßnahmen nur als Paket und nur bis zum Update.
Wie Sie die Grenze mit systemd setzen, steht unter Speichergrenzen mit systemd und cgroups; die Dauerlösung für den Alltag beschreibt memory_limit richtig setzen.
Wie hilft PHP SOS konkret?
Über den PHP-Patch-Service gehen wir so vor:
- Bestand prüfen: Wir erfassen jede PHP-Version auf dem Server, getrennt nach CLI, FPM und Apache-Modul, und testen, ob die Fix-Version läuft.
- Speichergrenzen ordnen: Wir prüfen, wo
memory_limitüberall gesetzt wird, und richten Pool- und Systemgrenzen so ein, dass sie zusammenpassen. - Übergang absichern: Wo das Update noch blockiert ist, setzen wir die Maßnahmen von php.net vollständig und gegen Überschreiben gesperrt.
- Nachweis liefern: Sie erhalten Versionen, Paketstände und Konfiguration vor und nach dem Eingriff schriftlich.
Häufige Fragen
Was bedeutet die Meldung „Allowed memory size exhausted“?
Ein Skript wollte mehr Speicher anfordern, als memory_limit erlaubt. PHP bricht die laufende Anfrage dann mit einem fatalen Fehler ab. Andere Anfragen und der Server selbst laufen weiter.
Gilt memory_limit für den ganzen Server?
Nein, die Grenze gilt je PHP-Prozess und Anfrage. Laufen 20 FPM-Worker mit je 256 MB Grenze, können sie zusammen theoretisch über 5 GB belegen. Die Gesamtgrenze muss deshalb über Pool-Größe, systemd oder Container gesetzt werden.
Was ist memory_hard_limit_percent?
Eine neue Direktive, die mit PHP 8.5.12, 8.4.27, 8.3.36 und 8.2.35 kam. Sie setzt eine harte Grenze als Prozentwert von memory_limit, die nie überschritten wird. memory_limit selbst ist seitdem eine weiche Grenze.
Schützt memory_limit=-1 vor PHP2Shell?
Nur teilweise. php.net nennt die Einstellung als Übergangsmaßnahme gegen CVE-2026-109618, ausdrücklich ohne vollständigen Schutz. Sie braucht zwingend eine Speichergrenze von außen, und das Update bleibt Pflicht.