# memory_limit og out-of-memory: Hvad der sker indeni

> PHP out of memory forklaret: hvordan memory_limit tæller, hvad der sker internt ved afbrydelsen, og hvad det betyder for CVE-2026-109618 og jeres servere.

Kilde: https://phpsos.de/da/php/out-of-memory/  
Status: 25.10.2026  
Udbyder: PHP SOS, PHP-nødhjælp og serversikkerhed. Akut hjælp på WhatsApp: https://wa.me/491736494914?text=Hej%20PHP%20SOS%2C%20vi%20har%20brug%20for%20hj%C3%A6lp%20med%20vores%20PHP-server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kort sagt:** En PHP out-of-memory-fejl opstår, når et script vil anmode om mere hukommelse, end indstillingen `memory_limit` tillader (standard: 128 MB pr. forespørgsel). PHP afbryder så forespørgslen med en fatal fejl og rydder op. Netop denne afbrydelses- og oprydningsvej var fejlbehæftet ved CVE-2026-109618, en af de to PHP2Shell-sårbarheder. Siden PHP 8.5.12, 8.4.27, 8.3.36 og 8.2.35 er `memory_limit` en blød grænse, suppleret af den hårde grænse `memory_hard_limit_percent`.

## Hvad betyder »Allowed memory size exhausted«?

Den kendte fejlmeddelelse lyder i meningen: »Allowed memory size of 134217728 bytes exhausted (tried to allocate …)«. Det første tal er den indstillede grænse i bytes, her 128 MB. Et script har altså forsøgt at optage hukommelse ud over denne grænse, f.eks. ved indlæsning af en stor fil, en enorm databaseforespørgsel eller på grund af en uendelig løkke.

Vigtigt for beslutningstagere: Grænsen gælder pr. PHP-proces og pr. forespørgsel, ikke for hele serveren. Den beskytter serveren mod, at et enkelt fejlbehæftet script bruger al hukommelsen. Den samlede belastning fremkommer først af antallet af samtidigt kørende workers. Ved 20 PHP-FPM-workers med hver 256 MB grænse er det regnet ud over 5 GB.

## Sådan tæller PHP hukommelse

PHP administrerer hukommelse til forespørgsler via en egen hukommelsesmanager, Zend Memory Manager. Den henter større blokke fra operativsystemet og fordeler dem internt til variabler, arrays og objekter. Mod denne reserverede værdi kontrollerer PHP `memory_limit`. Hukommelse, som en udvidelse anmoder om direkte hos operativsystemet, optræder ifølge manualen ikke i denne optælling.

I kan gøre værdierne synlige i koden:

```php
<?php
echo memory_get_usage(), PHP_EOL;       // hukommelse, der aktuelt er optaget af scriptet
echo memory_get_usage(true), PHP_EOL;   // reserveret af hukommelsesmanageren; mod den kontrollerer memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // hidtidig spidsværdi
unset($liste);
memory_reset_peak_usage();              // nulstil spidsværdien, fra PHP 8.2
```

Hvordan referencetælling og garbage collection frigiver hukommelsen igen, forklarer siden [Hukommelsesstyring i PHP](https://phpsos.de/da/php/speicherverwaltung/).

## Hvad der sker indeni ved out-of-memory

Forenklet forløber en hukommelsesafbrydelse i disse trin:

1. Scriptet anmoder om hukommelse, for eksempel til et nyt array-element eller ved indlæsning af forespørgselsdata.
2. Hukommelsesmanageren kontrollerer, om anmodningen overskrider grænsen.
3. Er det tilfældet, udløser PHP en fatal fejl og forlader den igangværende behandling straks, også midt i en halvt udført opgave.
4. Registrerede shutdown-funktioner kører endnu; med dem logger mange applikationer fejlen.
5. Til sidst rydder PHP op efter forespørgslen og frigiver dens hukommelse. Workeren står derefter klar til den næste forespørgsel.

Det ømtålelige punkt er trin 5. Oprydningen skal kunne håndtere datastrukturer, der kun var halvt oprettet ved afbrydelsen. En almindelig hukommelsesafbrydelse gælder ifølge PHP-projektets sikkerhedspolitik ikke som sårbarhed, så længe grænsen afviser anmodningen, og kun den aktuelle forespørgsel slutter. Ved CVE-2026-109618 var netop denne forudsætning brudt: Ifølge php.net kunne out-of-memory-tilstanden afbryde PHP, mens interne forespørgselsdata kun var delvist initialiseret, og oprydningen behandlede så ugyldige data som gyldige. Detaljer om udnyttelsen offentliggør vi ikke; vurderingen af sårbarheden står under [CVE-2026-109618](https://phpsos.de/da/php2shell/cve-2026-109618/).

## Den nye bløde og hårde hukommelsesgrænse

Med sikkerhedsudgivelserne af 21.10.2026 har PHP-projektet ændret adfærden. Ifølge manualen er `memory_limit` siden da en blød grænse: En anmodning, der overskrider den, må i de fleste tilfælde stadig afsluttes, før den fatale fejl følger. En separat hård grænse begrænser, hvor langt det må gå.

| Direktiv | Standard | Kan ændres | Betydning |
|---|---|---|---|
| `memory_limit` | 128M | INI_ALL | Hukommelsesgrænse pr. forespørgsel, `-1` = ingen grænse |
| `memory_hard_limit_percent` | ikke sat | INI_ALL | Hård grænse i procent af `memory_limit`, ny siden 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| `post_max_size` | 8M | INI_PERDIR | Maksimal størrelse af POST-data |
| `upload_max_filesize` | 2M | INI_PERDIR | Maksimal størrelse af en uploadet fil |

Et eksempel fra manualen: Ved `memory_limit=128M` og `memory_hard_limit_percent=150` ligger den hårde grænse på 192 MB. Manualen nævner samtidig direktivet som kendetegn: Kender en PHP-version det ikke, er den berørt af CVE-2026-109618 og CVE-2026-109619. En hurtig test for hver installeret PHP-version:

```bash
php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) betyder: direktivet er ukendt
```

Ved pakker fra distributioner med backport forbliver pakkens changelog det afgørende bevis, som beskrevet under [Kontrollér PHP-version og patch-status rigtigt](https://phpsos.de/da/php2shell/php-version-pruefen/). Kontrollér desuden PHP-FPM-binæren separat, for den kan have en anden version end kommandolinjen.

## Hukommelsesgrænser og PHP2Shell: Hvad administratorer nu skal være opmærksomme på

php.nets midlertidige foranstaltninger til CVE-2026-109618 drejer sig næsten alle om hukommelse og forespørgselsstørrelser. De mindsker risikoen, men erstatter ikke opdateringen:

```ini
; FPM-pool, f.eks. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M, hvis der er brug for uploads
php_admin_value[upload_max_filesize] = 6M  ; hold under post_max_size
```

Tre punkter er afgørende. For det første må ingen applikation, ingen mappe og ingen anden pool igen sætte en endelig grænse; php.net kræver udtrykkeligt denne kontrol. For det andet har en tjeneste med `memory_limit=-1` brug for en grænse udefra, via container eller cgroup, ifølge php.net bedst sådan, at kun den berørte worker afsluttes. `RLIMIT_AS` og `RLIMIT_DATA` er ifølge php.net uegnede. For det tredje anbefaler php.net grænser ved webserveren eller proxyen for forespørgselsstørrelse, antal felter, multipart-dele, headere og indlejringsdybde.

> **Vigtigt:**
> `memory_limit=-1` uden hukommelsesgrænse udefra kan lægge en server fuldstændigt ned ved høj belastning. Sæt de midlertidige foranstaltninger kun som en samlet pakke og kun indtil opdateringen.

Hvordan I sætter grænsen med systemd, står under [Sæt hukommelsesgrænser med systemd og cgroups](https://phpsos.de/da/blog/speichergrenzen-systemd-cgroups/); den varige løsning til hverdagen beskriver [Sæt memory_limit rigtigt](https://phpsos.de/da/blog/memory-limit-richtig-setzen/).

## Hvordan hjælper PHP SOS konkret?

Via [PHP-patchservicen](https://phpsos.de/da/leistungen/php-patch-service/) går vi frem på denne måde:

- **Kontrollere beholdningen:** Vi registrerer hver PHP-version på serveren, adskilt efter CLI, FPM og Apache-modul, og tester, om rettelsesversionen kører.
- **Ordne hukommelsesgrænser:** Vi undersøger, hvor `memory_limit` overalt sættes, og indretter pool- og systemgrænser, så de passer sammen.
- **Sikre overgangen:** Hvor opdateringen endnu er blokeret, sætter vi php.nets foranstaltninger fuldstændigt og spærret mod overskrivning.
- **Levere dokumentation:** I får versioner, pakkestatus og konfiguration før og efter indgrebet skriftligt.


## Ofte stillede spørgsmål

**Hvad betyder meldingen »Allowed memory size exhausted«?**  
Et script ville anmode om mere hukommelse, end memory_limit tillader. PHP afbryder så den igangværende forespørgsel med en fatal fejl. Andre forespørgsler og selve serveren kører videre.

**Gælder memory_limit for hele serveren?**  
Nej, grænsen gælder pr. PHP-proces og forespørgsel. Kører der 20 FPM-workers med hver 256 MB grænse, kan de teoretisk optage over 5 GB tilsammen. Den samlede grænse skal derfor sættes via poolstørrelse, systemd eller container.

**Hvad er memory_hard_limit_percent?**  
Et nyt direktiv, som kom med PHP 8.5.12, 8.4.27, 8.3.36 og 8.2.35. Det sætter en hård grænse som procentværdi af memory_limit, der aldrig overskrides. memory_limit selv er siden da en blød grænse.

**Beskytter memory_limit=-1 mod PHP2Shell?**  
Kun delvist. php.net nævner indstillingen som midlertidig foranstaltning mod CVE-2026-109618, udtrykkeligt uden fuldstændig beskyttelse. Den kræver ubetinget en hukommelsesgrænse udefra, og opdateringen forbliver et must.

## Kilder

- [PHP-manualen: Kerneindstillinger (memory_limit, memory_hard_limit_percent)](https://www.php.net/manual/en/ini.core.php)
- [PHP-manualen: memory_get_usage()](https://www.php.net/manual/en/function.memory-get-usage.php)
- [php.net: Sikkerhedsmeddelelser af 21.10.2026](https://www.php.net/)
