# memory_limit și Out-of-Memory: ce se întâmplă în interior

> PHP Out of Memory pe înțelesul tuturor: cum numără memory_limit, ce se întâmplă intern la oprire și ce înseamnă aceasta pentru CVE-2026-109618 și serverele dumneavoastră.

Sursa: https://phpsos.de/ro/php/out-of-memory/  
Stadiu: 25.10.2026  
Furnizor: PHP SOS, Asistență de urgență PHP și securitatea serverelor. Ajutor imediat pe WhatsApp: https://wa.me/491736494914?text=Bun%C4%83%20ziua%2C%20PHP%20SOS%2C%20avem%20nevoie%20de%20ajutor%20cu%20serverul%20nostru%20PHP.%20Firma%3A%20%E2%80%A6%20Site%3A%20%E2%80%A6

**Pe scurt:** O eroare PHP Out-of-Memory apare atunci când un script vrea să solicite mai multă memorie decât permite setarea `memory_limit` (implicit: 128 MB pentru fiecare cerere). PHP întrerupe atunci cererea cu o eroare fatală și curăță. Exact acest drum de întrerupere și de curățare era defectuos la CVE-2026-109618, una dintre cele două vulnerabilități PHP2Shell. Începând cu PHP 8.5.12, 8.4.27, 8.3.36 și 8.2.35, `memory_limit` este o limită moale, completată de limita dură `memory_hard_limit_percent`.

## Ce înseamnă „Allowed memory size exhausted”?

Cunoscutul mesaj de eroare sună, în esență: „Allowed memory size of 134217728 bytes exhausted (tried to allocate …)”. Primul număr este limita setată, în octeți, aici 128 MB. Un script a încercat deci să ocupe memorie peste această limită, de exemplu la încărcarea unui fișier mare, la o interogare uriașă a bazei de date sau printr-o buclă infinită.

Important pentru factorii de decizie: limita se aplică pentru fiecare proces PHP și fiecare cerere, nu întregului server. Ea protejează serverul de situația în care un singur script defectuos consumă toată memoria. Sarcina totală rezultă abia din numărul de workeri care rulează simultan. La 20 de workeri PHP-FPM cu câte o limită de 256 MB, aceasta înseamnă, calculat, peste 5 GB.

## Cum numără PHP memoria

PHP gestionează memoria cererilor printr-un manager de memorie propriu, Zend Memory Manager. Acesta preia blocuri mai mari de la sistemul de operare și le distribuie intern variabilelor, array-urilor și obiectelor. Față de această valoare rezervată verifică PHP `memory_limit`. Memoria pe care o extensie o solicită direct de la sistemul de operare nu apare, potrivit manualului, în această numărare.

Puteți face valorile vizibile în cod:

```php
<?php
echo memory_get_usage(), PHP_EOL;       // memoria ocupată în prezent de script
echo memory_get_usage(true), PHP_EOL;   // rezervată de managerul de memorie; față de ea verifică memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // valoarea maximă de până acum
unset($liste);
memory_reset_peak_usage();              // resetează valoarea maximă, din PHP 8.2
```

Cum eliberează numărarea referințelor și garbage collection-ul memoria la loc, explică pagina [Gestionarea memoriei în PHP](https://phpsos.de/ro/php/speicherverwaltung/).

## Ce se întâmplă în interior la Out-of-Memory

Simplificat, o oprire din cauza memoriei decurge în acești pași:

1. Scriptul solicită memorie, de exemplu pentru un nou element de array sau la citirea datelor cererii.
2. Managerul de memorie verifică dacă solicitarea depășește limita.
3. Dacă da, PHP declanșează o eroare fatală și părăsește imediat procesarea în curs, chiar în mijlocul unei sarcini pe jumătate îndeplinite.
4. Funcțiile shutdown înregistrate mai rulează; cu ele multe aplicații înregistrează eroarea în log.
5. La final, PHP curăță cererea și eliberează memoria ei. Workerul este apoi pregătit pentru următoarea cerere.

Punctul delicat este pasul 5. Curățarea trebuie să poată face față unor structuri de date care erau doar pe jumătate create în momentul opririi. O oprire obișnuită din cauza memoriei nu este considerată, potrivit politicii de securitate a proiectului PHP, o vulnerabilitate, atât timp cât limita respinge solicitarea și se încheie doar cererea curentă. La CVE-2026-109618, exact această presupunere era încălcată: potrivit php.net, starea Out-of-Memory putea întrerupe PHP în timp ce datele interne ale cererii erau inițializate doar parțial, iar curățarea trata apoi datele invalide ca valide. Nu publicăm detalii despre exploatare; încadrarea vulnerabilității se găsește la [CVE-2026-109618](https://phpsos.de/ro/php2shell/cve-2026-109618/).

## Noua limită moale și dură de memorie

Cu versiunile de securitate din 21.10.2026, proiectul PHP a schimbat comportamentul. Potrivit manualului, `memory_limit` este de atunci o limită moale: o solicitare care o depășește poate, în majoritatea cazurilor, să fie încă finalizată înainte să urmeze eroarea fatală. O limită dură separată restrânge cât de departe poate merge aceasta.

| Directivă | Implicit | Modificabilă | Semnificație |
|---|---|---|---|
| `memory_limit` | 128M | INI_ALL | limita de memorie pentru fiecare cerere, `-1` = fără limită |
| `memory_hard_limit_percent` | nesetată | INI_ALL | limita dură în procente din `memory_limit`, nouă din 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| `post_max_size` | 8M | INI_PERDIR | dimensiunea maximă a datelor POST |
| `upload_max_filesize` | 2M | INI_PERDIR | dimensiunea maximă a unui fișier încărcat |

Un exemplu din manual: la `memory_limit=128M` și `memory_hard_limit_percent=150`, limita dură este de 192 MB. Manualul indică directiva totodată ca semn de recunoaștere: dacă o versiune PHP nu o cunoaște, este afectată de CVE-2026-109618 și CVE-2026-109619. Un test rapid pentru fiecare versiune PHP instalată:

```bash
php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) înseamnă: directivă necunoscută
```

La pachetele din distribuții cu backport, changelog-ul pachetului rămâne dovada decisivă, așa cum este descris la [Verificarea corectă a versiunii PHP și a stării de patch](https://phpsos.de/ro/php2shell/php-version-pruefen/). Verificați în plus separat binarul PHP-FPM, deoarece acesta poate avea altă versiune decât linia de comandă.

## Limite de memorie și PHP2Shell: ce trebuie să urmărească administratorii acum

Măsurile de tranziție de la php.net privind CVE-2026-109618 gravitează aproape toate în jurul memoriei și al dimensiunilor cererilor. Ele reduc riscul, dar nu înlocuiesc actualizarea:

```ini
; pool FPM, de ex. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M, dacă sunt necesare upload-uri
php_admin_value[upload_max_filesize] = 6M  ; menține sub post_max_size
```

Trei puncte sunt aici decisive. În primul rând, nicio aplicație, niciun director și niciun alt pool nu are voie să seteze din nou o limită finită; php.net cere explicit acest control. În al doilea rând, un serviciu cu `memory_limit=-1` are nevoie de o limită din exterior, prin container sau cgroup, potrivit php.net cel mai bine astfel încât să fie încheiat doar workerul afectat. `RLIMIT_AS` și `RLIMIT_DATA` sunt, potrivit php.net, nepotrivite. În al treilea rând, php.net recomandă limite la serverul web sau la proxy pentru dimensiunea cererii, numărul de câmpuri, părțile multipart, antete și adâncimea de imbricare.

> **Important:**
> `memory_limit=-1` fără o limită de memorie din exterior poate paraliza complet un server la sarcină mare. Aplicați măsurile de tranziție doar ca pachet și doar până la actualizare.

Cum setați limita cu systemd, se găsește la [Limite de memorie cu systemd și cgroups](https://phpsos.de/ro/blog/speichergrenzen-systemd-cgroups/); soluția durabilă pentru practica de zi cu zi o descrie [Setarea corectă a memory_limit](https://phpsos.de/ro/blog/memory-limit-richtig-setzen/).

## Cum ajută PHP SOS concret?

Prin [serviciul PHP-Patch](https://phpsos.de/ro/leistungen/php-patch-service/) procedăm astfel:

- **Verificarea inventarului:** Inventariem fiecare versiune PHP de pe server, separat pentru CLI, FPM și modulul Apache, și testăm dacă rulează versiunea cu remedierea.
- **Ordonarea limitelor de memorie:** Verificăm unde este setat peste tot `memory_limit` și configurăm limitele pool-ului și ale sistemului astfel încât să se potrivească.
- **Securizarea tranziției:** Acolo unde actualizarea este încă blocată, aplicăm complet măsurile de la php.net, blocate împotriva suprascrierii.
- **Livrarea dovezii:** Primiți în scris versiunile, stările pachetelor și configurația dinainte și de după intervenție.


## Întrebări frecvente

**Ce înseamnă mesajul „Allowed memory size exhausted”?**  
Un script a vrut să solicite mai multă memorie decât permite memory_limit. PHP întrerupe atunci cererea în curs cu o eroare fatală. Celelalte cereri și serverul însuși continuă să ruleze.

**Se aplică memory_limit întregului server?**  
Nu, limita se aplică pentru fiecare proces PHP și fiecare cerere. Dacă rulează 20 de workeri FPM cu câte o limită de 256 MB, teoretic pot ocupa împreună peste 5 GB. Limita totală trebuie de aceea stabilită prin dimensiunea pool-ului, systemd sau container.

**Ce este memory_hard_limit_percent?**  
O directivă nouă, apărută cu PHP 8.5.12, 8.4.27, 8.3.36 și 8.2.35. Ea stabilește o limită dură, ca procent din memory_limit, care nu este depășită niciodată. Din acel moment, memory_limit însuși este o limită moale.

**Protejează memory_limit=-1 împotriva PHP2Shell?**  
Doar parțial. php.net indică această setare ca măsură de tranziție împotriva CVE-2026-109618, în mod explicit fără protecție completă. Ea necesită obligatoriu o limită de memorie din exterior, iar actualizarea rămâne obligatorie.

## Surse

- [Manualul PHP: setări de bază (memory_limit, memory_hard_limit_percent)](https://www.php.net/manual/en/ini.core.php)
- [Manualul PHP: memory_get_usage()](https://www.php.net/manual/en/function.memory-get-usage.php)
- [php.net: anunțuri de securitate din 21.10.2026](https://www.php.net/)
