Pojmem memory leaks se označují stavy, kdy aplikace není schopna uvolnit alokovanou paměť. Nedávno tento problém hlouběji rozebíral Roman -Dagi- Pichlík. A před pár dny jsem zjistil, jak katastrofálně je na tom PHP.

PHP

Trošku odbočím. Před každým vypuštěním nové verze Texy! ji testuji tak, že nechám převést několik tisíc připravených souborů a porovnávám získané výsledky s referenčními. Onehdy jsem během testování měl spuštěného Správce úloh, záložku Procesy. Řeknu vám, pěkně mi klesla čelist, když jsem zahlédl, že PHP si ukouslo 900MB RAM a stále chce víc. Cosi shnilého je v mé aplikaci, pomyslel jsem si, a jal se hledat problém.

Tak jsem testovací skript + knihovnu Texy! postupně redukoval a redukoval, až jsem to zredukoval na těchto pár řádků:

class MemoryLeakClass {
	var $ref;
}

$obj = new MemoryLeakClass();
$obj->ref = & $obj;
unset($obj);

Pokud si myslíte, že příkaz unset() uvolní paměť drženou objektem, jste na omylu. Neuvolní. Můžete si to ověřit tak, že spustíte tento lehce upravený příklad a budete ve Správci úloh sledovat využitou paměť:

class MemoryLeakClass {
	var $consumeBigMemory;
	var $ref;
}

$obj = new MemoryLeakClass();

// allocate 5MB
$obj->consumeBigMemory = str_repeat('*', 5e6);

$obj->ref = & $obj;
unset($obj);

// wait 10s
sleep(10);

Během čekání (sleep) je krásně vidět, že paměť zůstává blokovaná. To je mazec, co?

Příklad můžete modifikovat i tak, že vytvoříte dva objekty, které budou referencí odkazovat jeden na druhého. I když je společně zrušíte příkazem unset(), vzpomínka na ně zůstane v živé paměti.

Problém se týká prakticky všech verzí PHP, testoval jsem od 4.3.0 do 5.0.4. Prohledal jsem PHP Bugs a našel více než dva roky starý související Bug #22055 Memory leak with references in objects. Reakce jednoho z vývojářů mě dostala:

It won't be fixed in PHP 4 anyway as it has to do with the way objects

Nicméně ani v pětce to vyřešené není.

Nejvíc mě na tom celém trápí, že neznám způsob, jak ty objekty uvolnit. I když zruším $obj->ref a následně $obj, stejně to nepomůže. Takže … nevíte o nějaké učebnici Javy pro začátečníky? 🙂

Aktualizace o pár let později: tento problém vyřešil nový garbage collector v PHP 5.3