# memory_limit in Out-of-Memory: kaj se dogaja v notranjosti

> PHP Out of Memory razumljivo: kako šteje memory_limit, kaj se ob prekinitvi dogaja v ozadju in kaj to pomeni za CVE-2026-109618 ter vaše strežnike.

Vir: https://phpsos.de/sl/php/out-of-memory/  
Stanje: 25.10.2026  
Ponudnik: PHP SOS, Nujna pomoč za PHP in varnost strežnikov. Takojšnja pomoč po WhatsAppu: https://wa.me/491736494914?text=Pozdravljeni%2C%20PHP%20SOS%2C%20potrebujemo%20pomo%C4%8D%20z%20na%C5%A1im%20stre%C5%BEnikom%20PHP.%20Podjetje%3A%20%E2%80%A6%20Spletna%20stran%3A%20%E2%80%A6

**Na kratko:** Napaka PHP Out-of-Memory nastane, ko skripta želi zahtevati več pomnilnika, kot dovoljuje nastavitev `memory_limit` (privzeto: 128 MB na zahtevo). PHP nato zahtevo prekine s smrtno napako in pospravi. Prav ta pot prekinitve in čiščenja je bila pri CVE-2026-109618, eni od obeh ranljivosti PHP2Shell, napačna. Od PHP 8.5.12, 8.4.27, 8.3.36 in 8.2.35 je `memory_limit` mehka meja, dopolnjena s trdo mejo `memory_hard_limit_percent`.

## Kaj pomeni „Allowed memory size exhausted“?

Znano sporočilo o napaki se po pomenu glasi: „Allowed memory size of 134217728 bytes exhausted (tried to allocate …)“. Prva številka je nastavljena omejitev v bajtih, tu 128 MB. Skripta je torej poskusila zasesti pomnilnik čez to mejo, na primer pri nalaganju velike datoteke, ogromni poizvedbi v podatkovni bazi ali zaradi neskončne zanke.

Za odločevalce pomembno: meja velja za vsak proces PHP in vsako zahtevo, ne za celoten strežnik. Strežnik ščiti pred tem, da bi posamezna napačna skripta porabila ves pomnilnik. Skupna obremenitev izhaja šele iz števila hkrati tekočih workerjev. Pri 20 workerjih PHP-FPM z mejo po 256 MB je to računsko več kot 5 GB.

## Kako PHP šteje pomnilnik

PHP pomnilnik za zahteve upravlja prek lastnega upravljalnika pomnilnika, Zend Memory Manager. Večje bloke vzame pri operacijskem sistemu in jih interno razdeli spremenljivkam, poljem in objektom. Glede na to rezervirano vrednost PHP preverja `memory_limit`. Pomnilnik, ki ga razširitev zahteva neposredno pri operacijskem sistemu, se po priročniku v tem štetju ne pojavi.

Vrednosti lahko naredite vidne v kodi:

```php
<?php
echo memory_get_usage(), PHP_EOL;       // trenutno pomnilnik, ki ga zaseda skripta
echo memory_get_usage(true), PHP_EOL;   // rezervira upravljalnik pomnilnika; glede na to preverja memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // dosedanja najvišja vrednost
unset($liste);
memory_reset_peak_usage();              // ponastavitev najvišje vrednosti, od PHP 8.2
```

Kako štetje sklicev in garbage collection pomnilnik znova sprostita, razlaga stran [Upravljanje pomnilnika v PHP](https://phpsos.de/sl/php/speicherverwaltung/).

## Kaj se ob Out-of-Memory dogaja v notranjosti

Poenostavljeno prekinitev zaradi pomnilnika poteka v teh korakih:

1. Skripta zahteva pomnilnik, na primer za nov element polja ali pri branju podatkov zahteve.
2. Upravljalnik pomnilnika preveri, ali zahteva presega mejo.
3. Če je tako, PHP sproži smrtno napako in takoj zapusti tekočo obdelavo, tudi sredi napol opravljene naloge.
4. Registrirane funkcije za zaustavitev (shutdown) se še izvedejo; številne aplikacije z njimi zabeležijo napako.
5. Na koncu PHP zahtevo pospravi in sprosti njen pomnilnik. Worker je nato pripravljen za naslednjo zahtevo.

Občutljiva točka je korak 5. Čiščenje se mora znati spoprijeti s podatkovnimi strukturami, ki so bile ob prekinitvi šele napol ustvarjene. Običajna prekinitev zaradi pomnilnika po varnostni politiki projekta PHP ni varnostna vrzel, dokler meja zahtevo zavrne in se konča le trenutna zahteva. Pri CVE-2026-109618 je bila prav ta predpostavka kršena: po navedbah php.net je stanje Out-of-Memory lahko prekinilo PHP, medtem ko so bili notranji podatki zahteve le delno inicializirani, čiščenje pa je nato neveljavne podatke obravnavalo kot veljavne. Podrobnosti izkoriščanja ne objavljamo; uvrstitev ranljivosti je pod [CVE-2026-109618](https://phpsos.de/sl/php2shell/cve-2026-109618/).

## Nova mehka in trda meja pomnilnika

Z varnostnimi izdajami z dne 21. 10. 2026 je projekt PHP spremenil obnašanje. Po priročniku je `memory_limit` od takrat mehka meja: zahtevo, ki jo preseže, je v večini primerov še dovoljeno dokončati, preden sledi smrtna napaka. Ločena trda meja omejuje, kako daleč lahko to gre.

| Direktiva | Privzeto | Spremenljivo | Pomen |
|---|---|---|---|
| `memory_limit` | 128M | INI_ALL | meja pomnilnika na zahtevo, `-1` = brez meje |
| `memory_hard_limit_percent` | ni nastavljeno | INI_ALL | trda meja v odstotkih `memory_limit`, novo od 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| `post_max_size` | 8M | INI_PERDIR | največja velikost podatkov POST |
| `upload_max_filesize` | 2M | INI_PERDIR | največja velikost naložene datoteke |

Primer iz priročnika: pri `memory_limit=128M` in `memory_hard_limit_percent=150` je trda meja pri 192 MB. Priročnik direktivo hkrati navaja kot znak za prepoznavo: če je različica PHP ne pozna, sta jo prizadeli CVE-2026-109618 in CVE-2026-109619. Hiter test za vsako nameščeno različico PHP:

```bash
php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) pomeni: direktiva neznana
```

Pri paketih iz distribucij z backportom ostaja merodajno dokazilo dnevnik sprememb paketa, kot je opisano v [Pravilno preverjanje različice PHP in stanja popravkov](https://phpsos.de/sl/php2shell/php-version-pruefen/). Poleg tega ločeno preverite binarno datoteko PHP-FPM, saj ima lahko drugo različico kot ukazna vrstica.

## Meje pomnilnika in PHP2Shell: na kaj morajo skrbniki paziti zdaj

Prehodni ukrepi php.net za CVE-2026-109618 se skoraj vsi vrtijo okoli pomnilnika in velikosti zahtev. Tveganje zmanjšujejo, posodobitve pa ne nadomestijo:

```ini
; pool FPM, npr. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M, če je nalaganje potrebno
php_admin_value[upload_max_filesize] = 6M  ; ostati pod post_max_size
```

Pomembne so tri točke. Prvič, nobena aplikacija, noben imenik in noben drug pool ne sme znova nastaviti končne meje; php.net to kontrolo izrecno zahteva. Drugič, storitev z `memory_limit=-1` potrebuje zunanjo mejo, prek vsebnika ali cgroup, po php.net najbolje tako, da se konča samo prizadeti worker. `RLIMIT_AS` in `RLIMIT_DATA` sta po php.net neprimerna. Tretjič, php.net priporoča meje na spletnem strežniku ali proxyju za velikost zahteve, število polj, dele multipart, glave in globino gnezdenja.

> **Pomembno:**
> `memory_limit=-1` brez zunanje meje pomnilnika lahko strežnik pri veliki obremenitvi popolnoma ohromi. Prehodne ukrepe uvedite samo kot paket in samo do posodobitve.

Kako mejo nastaviti s systemd, je opisano v [Meje pomnilnika s systemd in cgroups](https://phpsos.de/sl/blog/speichergrenzen-systemd-cgroups/); trajno rešitev za vsakdan opisuje [Pravilna nastavitev memory_limit](https://phpsos.de/sl/blog/memory-limit-richtig-setzen/).

## Kako PHP SOS pomaga konkretno?

Prek [storitve popravljanja PHP](https://phpsos.de/sl/leistungen/php-patch-service/) ravnamo takole:

- **Preveriti stanje:** zajamemo vsako različico PHP na strežniku, ločeno po CLI, FPM in modulu Apache, ter preizkusimo, ali teče popravljena različica.
- **Urediti meje pomnilnika:** preverimo, kje vse je nastavljen `memory_limit`, in meje poolov ter sistema nastavimo tako, da se ujemajo.
- **Zavarovati prehod:** kjer je posodobitev še blokirana, ukrepe php.net uvedemo v celoti in zaklenjene proti prepisovanju.
- **Predložiti dokazilo:** različice, stanja paketov in konfiguracijo pred posegom in po njem prejmete pisno.


## Pogosta vprašanja

**Kaj pomeni sporočilo „Allowed memory size exhausted“?**  
Skripta je želela zahtevati več pomnilnika, kot dovoljuje memory_limit. PHP nato tekočo zahtevo prekine s smrtno napako. Druge zahteve in sam strežnik tečejo naprej.

**Ali memory_limit velja za celoten strežnik?**  
Ne, meja velja za vsak proces PHP in zahtevo. Če teče 20 workerjev FPM z mejo po 256 MB, lahko skupaj teoretično zasedejo več kot 5 GB. Skupno mejo je zato treba določiti prek velikosti poola, systemd ali vsebnika.

**Kaj je memory_hard_limit_percent?**  
Nova direktiva, ki je prišla s PHP 8.5.12, 8.4.27, 8.3.36 in 8.2.35. Določa trdo mejo kot odstotek memory_limit, ki je nikoli ni mogoče preseči. memory_limit sam je od takrat mehka meja.

**Ali memory_limit=-1 ščiti pred PHP2Shell?**  
Le delno. php.net nastavitev navaja kot prehodni ukrep proti CVE-2026-109618, izrecno brez popolne zaščite. Nujno potrebuje zunanjo mejo pomnilnika, posodobitev pa ostaja obvezna.

## Viri

- [Priročnik PHP: osnovne nastavitve (memory_limit, memory_hard_limit_percent)](https://www.php.net/manual/en/ini.core.php)
- [Priročnik PHP: memory_get_usage()](https://www.php.net/manual/en/function.memory-get-usage.php)
- [php.net: varnostna obvestila z dne 21. 10. 2026](https://www.php.net/)
