# memory_limit i Out-of-Memory: što se događa iznutra

> PHP Out of Memory razumljivo: kako memory_limit broji, što se interno događa pri prekidu i što to znači za CVE-2026-109618 i Vaše poslužitelje.

Izvor: https://phpsos.de/hr/php/out-of-memory/  
Stanje: 25.10.2026  
Pružatelj: PHP SOS, PHP hitna pomoć i sigurnost poslužitelja. Hitna pomoć putem WhatsAppa: https://wa.me/491736494914?text=Pozdrav%20PHP%20SOS%2C%20trebamo%20pomo%C4%87%20s%20na%C5%A1im%20PHP%20poslu%C5%BEiteljem.%20Tvrtka%3A%20%E2%80%A6%20Web-stranica%3A%20%E2%80%A6

**Ukratko:** PHP pogreška Out-of-Memory nastaje kad skripta želi zatražiti više memorije nego što postavka `memory_limit` dopušta (zadano: 128 MB po zahtjevu). PHP tada prekida zahtjev fatalnom pogreškom i čisti. Upravo je taj put prekida i čišćenja bio pogrešan kod CVE-2026-109618, jedne od dviju ranjivosti PHP2Shella. Od PHP-a 8.5.12, 8.4.27, 8.3.36 i 8.2.35 `memory_limit` je meka granica, dopunjena tvrdom granicom `memory_hard_limit_percent`.

## Što znači „Allowed memory size exhausted“?

Poznata poruka o pogrešci glasi otprilike: „Allowed memory size of 134217728 bytes exhausted (tried to allocate …)“. Prvi broj je postavljeno ograničenje u bajtovima, ovdje 128 MB. Skripta je dakle pokušala zauzeti memoriju preko te granice, primjerice pri učitavanju velike datoteke, golemog upita u bazu podataka ili zbog beskonačne petlje.

Važno za donositelje odluka: granica vrijedi po PHP procesu i zahtjevu, a ne za cijeli poslužitelj. Štiti poslužitelj od toga da jedna pogrešna skripta potroši svu memoriju. Ukupno opterećenje proizlazi tek iz broja istodobno aktivnih workera. S 20 PHP-FPM workera s granicom od po 256 MB to računski iznosi više od 5 GB.

## Kako PHP broji memoriju

PHP memorijom za zahtjeve upravlja vlastitim upraviteljem memorije, Zend Memory Managerom. On od operacijskog sustava uzima veće blokove i interno ih raspodjeljuje varijablama, poljima i objektima. Prema toj rezerviranoj vrijednosti PHP provjerava `memory_limit`. Memorija koju ekstenzija izravno traži od operacijskog sustava prema priručniku se u tom brojanju ne pojavljuje.

Vrijednosti možete učiniti vidljivima u kodu:

```php
<?php
echo memory_get_usage(), PHP_EOL;       // memorija koju skripta trenutačno zauzima
echo memory_get_usage(true), PHP_EOL;   // rezervirao upravitelj memorije; prema tome provjerava memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // dosadašnja najviša vrijednost
unset($liste);
memory_reset_peak_usage();              // vraćanje najviše vrijednosti na početak, od PHP-a 8.2
```

Kako brojanje referenci i garbage collection ponovno oslobađaju memoriju, objašnjava stranica [Upravljanje memorijom u PHP-u](https://phpsos.de/hr/php/speicherverwaltung/).

## Što se pri Out-of-Memoryju događa iznutra

Pojednostavljeno, prekid zbog memorije odvija se u ovim koracima:

1. Skripta traži memoriju, primjerice za novi element polja ili pri čitanju podataka zahtjeva.
2. Upravitelj memorije provjerava prekoračuje li zahtjev granicu.
3. Ako prekoračuje, PHP izaziva fatalnu pogrešku i odmah napušta tekuću obradu, čak i usred napola obavljenog zadatka.
4. Registrirane shutdown funkcije još se izvršavaju; pomoću njih mnoge aplikacije zapisuju pogrešku.
5. Na kraju PHP čisti zahtjev i oslobađa njegovu memoriju. Worker je nakon toga spreman za sljedeći zahtjev.

Osjetljiva točka je korak 5. Čišćenje se mora znati nositi sa strukturama podataka koje su pri prekidu bile tek napola stvorene. Obični prekid zbog memorije prema sigurnosnim smjernicama PHP projekta nije sigurnosna ranjivost, sve dok ograničenje odbija zahtjev i završava samo tekući zahtjev. Kod CVE-2026-109618 upravo je ta pretpostavka bila narušena: prema php.net stanje nedostatka memorije moglo je prekinuti PHP dok su interni podaci zahtjeva bili tek djelomično inicijalizirani, a čišćenje je nevaljane podatke tada tretiralo kao valjane. Pojedinosti iskorištavanja ne objavljujemo; razvrstavanje ranjivosti nalazi se na stranici [CVE-2026-109618](https://phpsos.de/hr/php2shell/cve-2026-109618/).

## Nova meka i tvrda granica memorije

Sigurnosnim izdanjima od 21. 10. 2026. PHP projekt promijenio je ponašanje. Prema priručniku `memory_limit` je od tada meka granica: zahtjev koji je prekorači u većini slučajeva smije se još dovršiti prije nego što slijedi fatalna pogreška. Zasebna tvrda granica ograničava dokle to smije ići.

| Direktiva | Zadano | Promjenjivo | Značenje |
|---|---|---|---|
| `memory_limit` | 128M | INI_ALL | granica memorije po zahtjevu, `-1` = bez granice |
| `memory_hard_limit_percent` | nije postavljeno | INI_ALL | tvrda granica u postocima od `memory_limit`, novo od 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| `post_max_size` | 8M | INI_PERDIR | najveća veličina POST podataka |
| `upload_max_filesize` | 2M | INI_PERDIR | najveća veličina učitane datoteke |

Primjer iz priručnika: uz `memory_limit=128M` i `memory_hard_limit_percent=150` tvrda granica iznosi 192 MB. Priručnik tu direktivu istodobno navodi kao prepoznatljivo obilježje: ako je neka verzija PHP-a ne poznaje, pogođena je ranjivostima CVE-2026-109618 i CVE-2026-109619. Brz test za svaku instaliranu verziju PHP-a:

```bash
php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) znači: direktiva je nepoznata
```

Kod paketa iz distribucija s backportom mjerodavni dokaz ostaje changelog paketa, kako je opisano na stranici [Ispravna provjera verzije i razine zakrpa PHP-a](https://phpsos.de/hr/php2shell/php-version-pruefen/). Provjerite uz to zasebno i PHP-FPM binarnu datoteku, jer može imati drukčiju verziju od naredbenog retka.

## Granice memorije i PHP2Shell: na što administratori sada paze

Prijelazne mjere php.net za CVE-2026-109618 gotovo se sve vrte oko memorije i veličina zahtjeva. Smanjuju rizik, ali ne zamjenjuju ažuriranje:

```ini
; FPM pool, npr. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M ako su uploadi potrebni
php_admin_value[upload_max_filesize] = 6M  ; držati ispod post_max_size
```

Pritom su odlučujuće tri točke. Prvo, nijedna aplikacija, direktorij ili drugi pool ne smije ponovno postaviti konačnu granicu; php.net izričito traži tu kontrolu. Drugo, usluga s `memory_limit=-1` treba vanjsku granicu, putem containera ili cgroupa, prema php.net najbolje tako da se prekida samo pogođeni worker. `RLIMIT_AS` i `RLIMIT_DATA` prema php.net nisu prikladni. Treće, php.net preporučuje granice na web-poslužitelju ili proxyju za veličinu zahtjeva, broj polja, multipart dijelove, zaglavlja i dubinu ugniježđenja.

> **Važno:**
> `memory_limit=-1` bez vanjske granice memorije može pri velikom opterećenju potpuno onesposobiti poslužitelj. Prijelazne mjere postavljajte samo kao paket i samo do ažuriranja.

Kako granicu postaviti sa systemdom, piše u članku [Ograničenja memorije sa systemdom i cgroupima](https://phpsos.de/hr/blog/speichergrenzen-systemd-cgroups/); trajno rješenje za svakodnevicu opisuje članak [Ispravno postavljanje memory_limit](https://phpsos.de/hr/blog/memory-limit-richtig-setzen/).

## Kako PHP SOS konkretno pomaže?

Putem [PHP patch servisa](https://phpsos.de/hr/leistungen/php-patch-service/) postupamo ovako:

- **Provjeriti stanje:** Bilježimo svaku verziju PHP-a na poslužitelju, odvojeno za CLI, FPM i Apache modul, i testiramo radi li verzija s ispravkom.
- **Urediti granice memorije:** Provjeravamo gdje se sve postavlja `memory_limit` i podešavamo granice poola i sustava tako da se uklapaju.
- **Osigurati prijelaz:** Gdje je ažuriranje još blokirano, mjere php.net postavljamo u cijelosti i zaključane protiv prepisivanja.
- **Isporučiti dokaz:** Verzije, stanja paketa i konfiguraciju prije i nakon zahvata dobivate pisanim putem.


## Česta pitanja

**Što znači poruka „Allowed memory size exhausted“?**  
Skripta je željela zatražiti više memorije nego što memory_limit dopušta. PHP tada prekida tekući zahtjev fatalnom pogreškom. Ostali zahtjevi i sâm poslužitelj nastavljaju raditi.

**Vrijedi li memory_limit za cijeli poslužitelj?**  
Ne, granica vrijedi po PHP procesu i zahtjevu. Ako radi 20 FPM workera s granicom od po 256 MB, zajedno teoretski mogu zauzeti više od 5 GB. Ukupna granica zato se mora postaviti veličinom poola, systemdom ili containerom.

**Što je memory_hard_limit_percent?**  
Nova direktiva koja je stigla s PHP-om 8.5.12, 8.4.27, 8.3.36 i 8.2.35. Postavlja tvrdu granicu kao postotak od memory_limit koja se nikad ne prekoračuje. memory_limit je od tada sâm meka granica.

**Štiti li memory_limit=-1 od PHP2Shella?**  
Samo djelomično. php.net tu postavku navodi kao prijelaznu mjeru protiv CVE-2026-109618, izričito bez potpune zaštite. Nužno joj treba vanjska granica memorije, a ažuriranje ostaje obvezno.

## Izvori

- [PHP priručnik: Temeljne postavke (memory_limit, memory_hard_limit_percent)](https://www.php.net/manual/en/ini.core.php)
- [PHP priručnik: memory_get_usage()](https://www.php.net/manual/en/function.memory-get-usage.php)
- [php.net: Sigurnosne obavijesti od 21. 10. 2026.](https://www.php.net/)
