# memory_limit a Out-of-Memory: co se děje uvnitř

> PHP Out of Memory srozumitelně: jak memory_limit počítá, co se při ukončení děje uvnitř a co to znamená pro CVE-2026-109618 a vaše servery.

Zdroj: https://phpsos.de/cs/php/out-of-memory/  
Stav: 25.10.2026  
Poskytovatel: PHP SOS, Nouzová pomoc pro PHP a bezpečnost serverů. Okamžitá pomoc přes WhatsApp: https://wa.me/491736494914?text=Dobr%C3%BD%20den%2C%20PHP%20SOS%2C%20pot%C5%99ebujeme%20pomoc%20s%20na%C5%A1%C3%ADm%20PHP%20serverem.%20Firma%3A%20%E2%80%A6%20Web%3A%20%E2%80%A6

**Stručně:** Chyba PHP Out-of-Memory vzniká, když chce skript vyžádat více paměti, než povoluje nastavení `memory_limit` (standardně 128 MB na požadavek). PHP pak požadavek ukončí fatální chybou a uklidí. Právě tato cesta ukončení a úklidu byla chybná u CVE-2026-109618, jedné ze dvou zranitelností PHP2Shell. Od PHP 8.5.12, 8.4.27, 8.3.36 a 8.2.35 je `memory_limit` měkký limit, doplněný pevným limitem `memory_hard_limit_percent`.

## Co znamená „Allowed memory size exhausted“?

Známé chybové hlášení zní v přeneseném smyslu: „Allowed memory size of 134217728 bytes exhausted (tried to allocate …)“. První číslo je nastavený limit v bajtech, zde 128 MB. Skript se tedy pokusil obsadit paměť nad tuto hranici, například při načítání velkého souboru, obrovském databázovém dotazu nebo kvůli nekonečné smyčce.

Pro rozhodovatele je důležité: limit platí pro každý proces PHP a každý požadavek, ne pro celý server. Chrání server před tím, aby jediný chybný skript spotřeboval veškerou paměť. Celkové zatížení vyplývá teprve z počtu současně běžících workerů. Při 20 workerech PHP-FPM s limitem 256 MB je to početně přes 5 GB.

## Jak PHP počítá paměť

PHP spravuje paměť pro požadavky vlastním správcem paměti, Zend Memory Managerem. Ten získává větší bloky od operačního systému a vnitřně je rozděluje proměnným, polím a objektům. Proti této rezervované hodnotě PHP kontroluje `memory_limit`. Paměť, kterou si rozšíření vyžádá přímo u operačního systému, se podle příručky v tomto počítání neobjeví.

Hodnoty můžete zviditelnit v kódu:

```php
<?php
echo memory_get_usage(), PHP_EOL;       // paměť aktuálně obsazená skriptem
echo memory_get_usage(true), PHP_EOL;   // rezervováno správcem paměti; proti tomu kontroluje memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // dosavadní maximum
unset($liste);
memory_reset_peak_usage();              // vynulovat maximum, od PHP 8.2
```

Jak počítání referencí a garbage collection paměť opět uvolňují, vysvětluje stránka [Správa paměti v PHP](https://phpsos.de/cs/php/speicherverwaltung/).

## Co se při Out-of-Memory děje uvnitř

Zjednodušeně probíhá ukončení kvůli paměti v těchto krocích:

1. Skript si vyžádá paměť, například pro nový prvek pole nebo při načítání dat požadavku.
2. Správce paměti zkontroluje, zda požadavek překračuje limit.
3. Pokud ano, PHP vyvolá fatální chybu a okamžitě opustí probíhající zpracování, i uprostřed napůl hotového úkolu.
4. Registrované shutdown funkce ještě proběhnou; mnoho aplikací v nich chybu zaprotokoluje.
5. Na konci PHP požadavek uklidí a uvolní jeho paměť. Worker je poté připraven na další požadavek.

Choulostivým místem je krok 5. Úklid si musí poradit s datovými strukturami, které byly při ukončení teprve napůl vytvořeny. Běžné ukončení kvůli paměti se podle bezpečnostní politiky projektu PHP nepovažuje za bezpečnostní zranitelnost, pokud limit požadavek odmítne a skončí jen aktuální požadavek. U CVE-2026-109618 byl právě tento předpoklad porušen: podle php.net mohl stav nedostatku paměti přerušit PHP ve chvíli, kdy byla interní data požadavku inicializována jen částečně, a úklid pak zacházel s neplatnými daty jako s platnými. Podrobnosti zneužití nezveřejňujeme; zařazení zranitelnosti najdete v [CVE-2026-109618](https://phpsos.de/cs/php2shell/cve-2026-109618/).

## Nový měkký a pevný limit paměti

S bezpečnostními vydáními z 21. 10. 2026 projekt PHP chování změnil. Podle příručky je `memory_limit` od té doby měkký limit: požadavek, který jej překročí, smí být ve většině případů ještě dokončen, než následuje fatální chyba. Samostatný pevný limit určuje, jak daleko to smí zajít.

| Direktiva | Výchozí | Lze měnit | Význam |
|---|---|---|---|
| `memory_limit` | 128M | INI_ALL | limit paměti na požadavek, `-1` = bez limitu |
| `memory_hard_limit_percent` | nenastaveno | INI_ALL | pevný limit v procentech z `memory_limit`, nové od 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| `post_max_size` | 8M | INI_PERDIR | maximální velikost dat POST |
| `upload_max_filesize` | 2M | INI_PERDIR | maximální velikost nahraného souboru |

Příklad z příručky: při `memory_limit=128M` a `memory_hard_limit_percent=150` leží pevný limit na 192 MB. Příručka tuto direktivu zároveň uvádí jako poznávací znamení: pokud ji verze PHP nezná, je CVE-2026-109618 a CVE-2026-109619 postižena. Rychlý test pro každou nainstalovanou verzi PHP:

```bash
php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) znamená: direktiva neznámá
```

U balíčků z distribucí s backportem zůstává rozhodujícím důkazem changelog balíčku, jak popisuje článek [Správná kontrola verze PHP a stavu záplat](https://phpsos.de/cs/php2shell/php-version-pruefen/). Zkontrolujte navíc samostatně binárku PHP-FPM, protože může mít jinou verzi než příkazová řádka.

## Limity paměti a PHP2Shell: čeho si nyní všímat

Přechodná opatření php.net k CVE-2026-109618 se téměř všechna točí kolem paměti a velikostí požadavků. Snižují riziko, ale aktualizaci nenahrazují:

```ini
; pool FPM, např. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M, pokud jsou nutná nahrávání
php_admin_value[upload_max_filesize] = 6M  ; držet pod post_max_size
```

Rozhodující jsou tři body. Zaprvé, žádná aplikace, žádný adresář ani jiný pool nesmí znovu nastavit konečný limit; php.net tuto kontrolu výslovně vyžaduje. Zadruhé, služba s `memory_limit=-1` potřebuje limit zvenčí, přes kontejner nebo cgroup, podle php.net nejlépe tak, aby se ukončil jen dotčený worker. `RLIMIT_AS` a `RLIMIT_DATA` jsou podle php.net nevhodné. Zatřetí, php.net doporučuje limity na webovém serveru nebo proxy pro velikost požadavku, počet polí, části multipart, hlavičky a hloubku vnoření.

> **Důležité:**
> `memory_limit=-1` bez limitu paměti zvenčí může při vysoké zátěži server úplně ochromit. Přechodná opatření nastavujte jen jako balík a jen do aktualizace.

Jak limit nastavit pomocí systemd, najdete v článku [Limity paměti pomocí systemd a cgroups](https://phpsos.de/cs/blog/speichergrenzen-systemd-cgroups/); trvalé řešení pro každodenní provoz popisuje článek [Správné nastavení memory_limit](https://phpsos.de/cs/blog/memory-limit-richtig-setzen/).

## Jak konkrétně pomáhá PHP SOS?

Prostřednictvím [služby záplatování PHP](https://phpsos.de/cs/leistungen/php-patch-service/) postupujeme takto:

- **Zkontrolovat stav:** Zjistíme každou verzi PHP na serveru, odděleně pro CLI, FPM a modul Apache, a otestujeme, zda běží opravená verze.
- **Uspořádat limity paměti:** Zkontrolujeme, kde všude se `memory_limit` nastavuje, a nastavíme limity poolů a systému tak, aby si odpovídaly.
- **Zajistit přechodné období:** Kde je aktualizace ještě blokována, nastavíme opatření php.net kompletně a zablokovaná proti přepsání.
- **Dodat doklad:** Verze, stavy balíčků a konfiguraci před zásahem a po něm obdržíte písemně.


## Časté dotazy

**Co znamená hlášení „Allowed memory size exhausted“?**  
Skript chtěl vyžádat více paměti, než povoluje memory_limit. PHP pak probíhající požadavek ukončí fatální chybou. Ostatní požadavky i samotný server běží dál.

**Platí memory_limit pro celý server?**  
Ne, limit platí pro každý proces PHP a požadavek. Pokud běží 20 workerů FPM s limitem 256 MB, mohou teoreticky společně obsadit přes 5 GB. Celkový limit je proto nutné nastavit přes velikost poolu, systemd nebo kontejner.

**Co je memory_hard_limit_percent?**  
Nová direktiva, která přišla s PHP 8.5.12, 8.4.27, 8.3.36 a 8.2.35. Nastavuje pevný limit jako procento z memory_limit, který se nikdy nepřekročí. memory_limit je od té doby měkký limit.

**Chrání memory_limit=-1 před PHP2Shell?**  
Jen částečně. php.net toto nastavení uvádí jako přechodné opatření proti CVE-2026-109618, výslovně bez úplné ochrany. Nutně potřebuje limit paměti zvenčí a aktualizace zůstává povinná.

## Zdroje

- [Příručka PHP: Základní nastavení (memory_limit, memory_hard_limit_percent)](https://www.php.net/manual/en/ini.core.php)
- [Příručka PHP: memory_get_usage()](https://www.php.net/manual/en/function.memory-get-usage.php)
- [php.net: Bezpečnostní oznámení z 21. 10. 2026](https://www.php.net/)
