Утечки памяти обычно не беспокоят PHP-разработчиков. Типичное приложение обрабатывает один запрос и работает не больше секунды. После этого вся использованная им память освобождается. Даже если приложение кушает слишком много, максимум, разработчик упирается в memory_limit, выставленный хостером, что решить в общем случае довольно просто: как только переменная становится не нужна, очищаем память, занимаемую ей, при помощи unset.
Однако, при выполнении ресурсоёмких задач (например, обработки большого количества данных) или запуске PHP как демона проблема утечек встаёт очень остро.
В PHP 5.2 нет полноценного сборщика мусора. Вместо него используется подсчёт ссылок.
Все значения переменных хранятся в памяти. И чтобы занимать как можно меньше места, переменные с одинаковыми значениями просто ссылаются на одну и ту же область памяти. При этом количество ссылок подсчитывается и, как только оно становится равно нулю, память освобождается.
$a = 10;
$b = $a;
unset($a);
$a = 10;
$b = $a;
$b = 1;
В PHP 5.2 причиной утечек являются циклические ссылки:
class A {
private $b;
function __construct(){
$this->b = new B($this);
}
}
class B {
private $a;
function __construct($a){
$this->a = $a;
}
}
$i=1;
while($i<=1000){
$a = new A();
unset($a);
echo $i."\t".memory_get_usage()."\n";
$i++;
}
Исправляется это явным уничтожением ссылки на B при помощи unset:
class A {
private $b;
function __construct(){
$this->b = new B($this);
}
function __destruct(){
unset($this->b);
}
}
class B {
private $a;
function __construct($a){
$this->a = $a;
}
}
$i=1;
while($i<=1000){
$a = new A();
unset($a);
echo $i."\t".memory_get_usage()."\n";
$i++;
}
В PHP 5.3 более умный сборщик мусора, который умеет находить и подчищать
последствия использования циклических ссылок. Однако,
поиск таких ссылок занимает
значительное время и зависит от количества «неподчищенных» ссылок. Плюс к этому работает
сборщик не постоянно, а срабатывает только при наполнении буфера ссылок. То есть до его срабатывания какое-то количество памяти всё-таки успевает утекать.
На заметку. Посмотреть, сколько памяти кушает ваше приложение можно при помощи следующих функций:
memory_get_usage() — использованная скриптом память в байтах в момент вызова функции.
memory_get_usage(true) — использованная скриптом и менеджером памяти PHP память в байтах в момент вызова функции.
memory_get_peak_usage() — максимальное количество памяти в байтах, использованной скриптом с запуска скрипта до момента вызова функции.
memory_get_peak_usage(true) — максимальное количество памяти в байтах, использованной скриптом и менеджером памяти PHP с запуска скрипта до момента вызова функции.