Actuele situatie: PHP2Shell. Twee kritieke PHP-kwetsbaarheden (CVSS 9.2) maken schadelijke code zonder inloggen mogelijk. Patches sinds 21-10-2026.Wat u nu moet doen →

memory_limit en out-of-memory: wat er van binnen gebeurt

Wat gebeurt er als een PHP-script tegen memory_limit aanloopt? Werking, de nieuwe harde geheugengrens sinds de oktoberpatches en het verband met CVE-2026-109618.

Stand 5 min. leestijdPHP-kennis

Kort gezegd: Een PHP-out-of-memory-fout ontstaat wanneer een script meer geheugen wil aanvragen dan de instelling memory_limit toestaat (standaard: 128 MB per verzoek). PHP breekt het verzoek dan af met een fatale fout en ruimt op. Juist deze afbreek- en opruimroute was bij CVE-2026-109618, een van de twee PHP2Shell-lekken, foutief. Sinds PHP 8.5.12, 8.4.27, 8.3.36 en 8.2.35 is memory_limit een zachte grens, aangevuld met de harde grens memory_hard_limit_percent.

Wat betekent „Allowed memory size exhausted”?

De bekende foutmelding luidt in grote lijnen: „Allowed memory size of 134217728 bytes exhausted (tried to allocate …)”. Het eerste getal is de ingestelde limiet in bytes, hier 128 MB. Een script heeft dus geprobeerd geheugen te gebruiken boven deze grens, bijvoorbeeld bij het laden van een groot bestand, een enorme databasequery of door een oneindige lus.

Belangrijk voor beslissers: de grens geldt per PHP-proces en per verzoek, niet voor de hele server. Ze beschermt de server ertegen dat één foutief script al het geheugen opgebruikt. De totale belasting volgt pas uit het aantal gelijktijdig draaiende workers. Bij 20 PHP-FPM-workers met elk een grens van 256 MB is dat rekenkundig meer dan 5 GB.

Hoe PHP geheugen telt

PHP beheert geheugen voor verzoeken via een eigen geheugenmanager, de Zend Memory Manager. Die haalt grotere blokken op bij het besturingssysteem en verdeelt ze intern over variabelen, arrays en objecten. Aan deze gereserveerde waarde toetst PHP het memory_limit. Geheugen dat een extensie rechtstreeks bij het besturingssysteem aanvraagt, komt volgens de handleiding in deze telling niet voor.

U kunt de waarden in de code zichtbaar maken:

<?php
echo memory_get_usage(), PHP_EOL;       // momenteel door het script in beslag genomen geheugen
echo memory_get_usage(true), PHP_EOL;   // door de geheugenmanager gereserveerd; hieraan toetst memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // tot nu toe hoogste waarde
unset($liste);
memory_reset_peak_usage();              // hoogste waarde terugzetten, vanaf PHP 8.2

Hoe referentietelling en garbage collection het geheugen weer vrijgeven, legt de pagina Geheugenbeheer in PHP uit.

Wat er bij out-of-memory van binnen gebeurt

Vereenvoudigd verloopt een geheugenafbreking in deze stappen:

  1. Het script vraagt geheugen aan, bijvoorbeeld voor een nieuw array-element of bij het inlezen van verzoekgegevens.
  2. De geheugenmanager controleert of de aanvraag de grens overschrijdt.
  3. Is dat het geval, dan veroorzaakt PHP een fatale fout en verlaat de lopende verwerking onmiddellijk, ook midden in een half afgeronde taak.
  4. Geregistreerde shutdown-functies draaien nog; daarmee leggen veel toepassingen de fout vast.
  5. Aan het einde ruimt PHP het verzoek op en geeft het geheugen ervan vrij. De worker staat daarna klaar voor het volgende verzoek.

Het kritieke punt is stap 5. Het opruimen moet kunnen omgaan met gegevensstructuren die bij de afbreking pas half waren aangelegd. Een gewone geheugenafbreking geldt volgens het beveiligingsbeleid van het PHP-project niet als beveiligingslek, zolang de limiet de aanvraag weigert en alleen het huidige verzoek eindigt. Bij CVE-2026-109618 was precies deze aanname geschonden: volgens php.net kon de out-of-memory-toestand PHP onderbreken terwijl interne verzoekgegevens maar gedeeltelijk waren geïnitialiseerd, en behandelde het opruimen ongeldige gegevens vervolgens als geldig. Details over het misbruik publiceren wij niet; de duiding van het lek staat onder CVE-2026-109618.

De nieuwe zachte en harde geheugengrens

Met de beveiligingsreleases van 21 oktober 2026 heeft het PHP-project het gedrag gewijzigd. Volgens de handleiding is memory_limit sindsdien een zachte grens: een aanvraag die haar overschrijdt, mag in de meeste gevallen nog worden afgerond voordat de fatale fout volgt. Een aparte harde grens begrenst hoe ver dat mag gaan.

Directive Standaard Wijzigbaar Betekenis
memory_limit 128M INI_ALL geheugengrens per verzoek, -1 = geen grens
memory_hard_limit_percent niet ingesteld INI_ALL harde grens in procenten van memory_limit, nieuw sinds 8.5.12, 8.4.27, 8.3.36, 8.2.35
post_max_size 8M INI_PERDIR maximale grootte van de POST-gegevens
upload_max_filesize 2M INI_PERDIR maximale grootte van een geüpload bestand

Een voorbeeld uit de handleiding: bij memory_limit=128M en memory_hard_limit_percent=150 ligt de harde grens op 192 MB. De handleiding noemt de directive tegelijk als herkenningsteken: kent een PHP-versie haar niet, dan wordt ze door CVE-2026-109618 en CVE-2026-109619 getroffen. Een snelle test voor elke geïnstalleerde PHP-versie:

php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) betekent: directive onbekend

Bij pakketten uit distributies met backport blijft de pakket-changelog het bepalende bewijs, zoals beschreven onder PHP-versie en patchstatus goed controleren. Controleer bovendien de PHP-FPM-binary afzonderlijk, want die kan een andere versie hebben dan de opdrachtregel.

Geheugengrenzen en PHP2Shell: waar beheerders nu op letten

De overgangsmaatregelen van php.net voor CVE-2026-109618 draaien bijna allemaal om geheugen en verzoekgroottes. Ze verkleinen het risico, maar vervangen de update niet:

; FPM-pool, bijv. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M als uploads nodig zijn
php_admin_value[upload_max_filesize] = 6M  ; onder post_max_size houden

Drie punten zijn daarbij beslissend. Ten eerste mag geen toepassing, geen map en geen andere pool opnieuw een eindige grens instellen; php.net eist uitdrukkelijk deze controle. Ten tweede heeft een dienst met memory_limit=-1 een grens van buitenaf nodig, via container of cgroup, volgens php.net bij voorkeur zo dat alleen de getroffen worker wordt beëindigd. RLIMIT_AS en RLIMIT_DATA zijn volgens php.net ongeschikt. Ten derde adviseert php.net grenzen op de webserver of proxy voor verzoekgrootte, aantal velden, multipart-delen, headers en nestingdiepte.

Belangrijk

memory_limit=-1 zonder geheugengrens van buitenaf kan een server bij hoge belasting volledig lamleggen. Voer de overgangsmaatregelen alleen als pakket door en alleen tot de update.

Hoe u de grens met systemd instelt, staat onder Geheugengrenzen met systemd en cgroups; de blijvende oplossing voor de dagelijkse praktijk beschrijft memory_limit goed instellen.

Hoe helpt PHP SOS concreet?

Via de PHP-patchservice gaan wij als volgt te werk:

  • Bestand controleren: Wij inventariseren elke PHP-versie op de server, gescheiden naar CLI, FPM en Apache-module, en testen of de fix-versie draait.
  • Geheugengrenzen ordenen: Wij controleren waar memory_limit overal wordt ingesteld en richten pool- en systeemgrenzen zo in dat ze bij elkaar passen.
  • Overgang beveiligen: Waar de update nog geblokkeerd is, voeren wij de maatregelen van php.net volledig door en vergrendeld tegen overschrijven.
  • Bewijs leveren: U ontvangt versies, pakketstanden en configuratie vóór en na de ingreep schriftelijk.

Veelgestelde vragen

Wat betekent de melding „Allowed memory size exhausted”?

Een script wilde meer geheugen aanvragen dan memory_limit toestaat. PHP breekt het lopende verzoek dan af met een fatale fout. Andere verzoeken en de server zelf blijven doorlopen.

Geldt memory_limit voor de hele server?

Nee, de grens geldt per PHP-proces en per verzoek. Draaien er 20 FPM-workers met elk een grens van 256 MB, dan kunnen ze samen theoretisch meer dan 5 GB in beslag nemen. De totale grens moet daarom via poolgrootte, systemd of container worden ingesteld.

Wat is memory_hard_limit_percent?

Een nieuwe directive die met PHP 8.5.12, 8.4.27, 8.3.36 en 8.2.35 kwam. Ze stelt een harde grens in als percentage van memory_limit, die nooit wordt overschreden. memory_limit zelf is sindsdien een zachte grens.

Beschermt memory_limit=-1 tegen PHP2Shell?

Slechts gedeeltelijk. php.net noemt de instelling als overgangsmaatregel tegen CVE-2026-109618, uitdrukkelijk zonder volledige bescherming. Ze vereist verplicht een geheugengrens van buitenaf, en de update blijft verplicht.

Bronnen

Direct contact

Elk uur telt. Schrijf ons nu.

Beschrijf kort het systeem, de PHP-versie en wat u opmerkt. Wij nemen contact op, brengen de situatie in kaart en werken op afstand tot het incident is afgerond en gedocumenteerd.

Directe hulp