php-memprof — это быстрое и точное расширение профилирования памяти для PHP, которое можно использовать для поиска причин утечек памяти.
Расширение отслеживает выделение и освобождение блоков памяти, чтобы сообщить об объеме памяти, утекшей каждой функцией, методом или файлом в программе.
Сообщает о несвободной памяти в произвольных точках программы.
Дамп профиля в форматах callgrind, pprof или необработанного массива.
Может отслеживать память, выделенную самим PHP, а также собственным malloc.
php-memprof зависит от libjudy и sys/queue.h.
В дистрибутивах на основе Debian зависимости можно установить с помощью:
# Debian or Ubuntu: apt install libjudy-dev
На Альпийском:
# Alpine apk add judy-dev bsd-compat-headers
В MacOS:
# install libjudy dependency: brew install traildb/judy/judy
Обязательно установите зависимости, а затем:
pecl install memprof
В MacOS: JUDY_DIR=$(brew --prefix Traildb/judy/judy) pecl install memprof
Примечание. Если libjudy установлена по нестандартному пути (не /usr или /usr/local), используйте метод ручной установки, указанный ниже.
Обязательно установите зависимости, а затем:
Загрузите исходный код и выполните следующие команды в исходном каталоге:
phpize ./configure make make install
Примечание. Если libjudy установлена по нестандартному пути (не /usr или /usr/local), вы можете указать его следующим образом:
./configure --with-judy-dir=/opt/homebrew/Cellar/judy/1.0.5
Пользователи Arch Linux могут предпочесть установить неофициальный пакет php-memprof с помощью makepkg
или предпочитаемого ими помощника AUR. Если вы используете yay
, например:
yay -S php-memprof
Пожалуйста, сообщайте о любых проблемах с этим пакетом на его странице AUR.
Расширение можно загрузить в командной строке всего для одного скрипта:
php -dextension=memprof.so script.php
Или навсегда в php.ini:
extension=memprof.so
Расширение не требует дополнительных затрат, когда оно не профилируется, поэтому его можно загружать по умолчанию в средах разработки.
Самый простой способ использовать memprof
— позволить ему сохранять профиль памяти при превышении предела памяти программы.
dump_on_limit
. Профилирование в режиме dump_on_limit
включается при запуске запроса, если одно из следующих условий истинно:
Переменная среды MEMPROF_PROFILE
равна dump_on_limit
$_GET["MEMPROF_PROFILE"]
равен dump_on_limit
$_POST["MEMPROF_PROFILE"]
равен dump_on_limit
Для сценариев командной строки мы можем установить переменную среды:
MEMPROF_PROFILE=dump_on_limit php test.php
Для веб-скриптов мы можем установить переменную $_GET
:
curl http://127.0.0.1/test.php?MEMPROF_PROFILE=dump_on_limit
Или переменная $_POST
:
curl -d MEMPROF_PROFILE=dump_on_limit http://127.0.0.1/test.php
Примечание. Функцию
memprof_enabled_flags()
можно вызвать, чтобы проверить, включено ли в данный момент профилирование в режимеdump_on_limit
.
В этом режиме memprof
автоматически сохранит профиль, если программа превысит лимит памяти (когда PHP выдает ошибку типа Fatal error: Allowed memory size of 15728640 bytes exhausted (tried to allocate 1024 bytes)
).
По умолчанию профиль сохраняется в файле с именем memprof.callgrind.*
в /tmp
или C:WindowsTemp
.
Рекомендуемый способ визуализации результата — использовать Kcachegrind (в Linux) или Qcachegrind (в MacOS, Windows). Google Perftools также поддерживаются. См. документацию memprof_dump_callgrind()
и вариантов.
В большинстве дистрибутивов имеется готовый к установке пакет kcachegrind
.
Например, Ubuntu или Debian:
sudo apt install kcachegrind
В других дистрибутивах, скорее всего, также есть пакет, готовый к установке.
Используйте Homebrew: https://formulae.brew.sh/formula/qcachegrind.
Загрузите его с https://sourceforge.net/projects/qcachegrindwin/.
Профилирование включается при запуске запроса, если выполняется одно из следующих условий:
Переменная среды MEMPROF_PROFILE
не пуста.
$_GET["MEMPROF_PROFILE"]
не пуст.
$_POST["MEMPROF_PROFILE"]
не пуст.
Переменная MEMPROF_PROFILE
принимает список флагов, разделенных запятыми.
Примеры допустимых значений MEMPROF_PROFILE
:
1
: непусто: профилирование включено.
dump_on_limit
: профилирование включено, дамп будет ограничен пределом памяти.
native
: профилирование включено, будет профилироваться собственное распределение
dump_on_limit,native
: профилирование включено, будет профилироваться собственное распределение, будет выгружаться по лимиту памяти.
Список допустимых флагов:
dump_on_limit
: выгрузит профиль в формате callgrind в /tmp
или C:WindowsTemp
. Выходной каталог можно изменить с помощью ini-настройки memprof.output_dir
.
native
: будет профилировать собственные распределения malloc()
, а не только PHP (это не потокобезопасно, см. ниже).
Memprof по умолчанию не отслеживает собственные выделения, но это можно включить, установив для MEMPROF_PROFILE
native
.
Собственные выделения — это выделения, выполняемые за пределами собственного распределителя памяти PHP. Обычно внешние библиотеки, такие как libxml2 (используемые в расширении DOM), выполняют собственное распределение. PHP также может самостоятельно выделять постоянные ресурсы.
Включение встроенного отслеживания выделения будет профилировать эти выделения в дополнение к собственным выделениям PHP.
Обратите внимание: когда встроенное отслеживание включено, программа выйдет из строя, если собственная библиотека использует потоки, поскольку базовые перехватчики не являются потокобезопасными.
Формат выходного файла определяется ini-настройкой memprof.output_format
. Возможные варианты:
callgrind
(по умолчанию)
pprof
Примечание . Это может быть доступно только в том случае, если расширение собрано из исходного кода (а не установлено с помощью pecl), начиная с #101.
Возвращает, включено ли в данный момент профилирование памяти (см. выше).
Возвращает, включено ли профилирование памяти и какие функции профилирования (см. выше).
Сбрасывает текущий профиль в формате callgrind. Результат можно визуализировать с помощью таких инструментов, как KCacheGrind или QCacheGrind.
<phpmemprof_dump_callgrind(fopen("выход", "w"));
Вот скриншот QcacheGrind:
Сбрасывает текущий профиль в формате pprof.
<?phpmemprof_dump_pprof(fopen("profile.heap", "w"));
Файл можно визуализировать с помощью инструмента pprof
от google-perftools. (Инструкции по установке см. ниже.)
Отобразить аннотированный график вызовов в веб-браузере или в gv
:
$ pprof --web profile.heap $ # or: $ pprof --gv profile.heap
Выведите по одной строке для каждой функции, отсортированной по использованию собственной памяти:
$ pprof --text profile.heap
pprof
: Ubuntu: apt install google-perftools
. В Ubuntu инструмент называется google-pprof
, поэтому в приведенных выше примерах вам необходимо заменить pprof
на google-pprof
.
Возвращает массив, представляющий текущий профиль.
<php$dump = memprof_dump_array();
Массив предоставляет следующую информацию:
Инклюзивная и эксклюзивная память, утекшая из функций (считая только ту память, которая еще не освобождена при вызове memprof_dump_array)
Подсчет инклюзивных и эксклюзивных блоков функций (количество выделений; подсчет только тех блоков, которые еще не освобождены при вызове memprof_dump_array)
Данные представлены в стеках вызовов. Таким образом, если функция вызывается из нескольких мест, можно увидеть, какой путь вызова вызвал большую утечку памяти.
Array ( [memory_size] => 11578 [blocks_count] => 236 [memory_size_inclusive] => 10497691 [blocks_count_inclusive] => 244 [calls] => 1 [called_functions] => Array ( [main] => Array ( [memory_size] => 288 [blocks_count] => 3 [memory_size_inclusive] => 10486113 [blocks_count_inclusive] => 8 [calls] => 1 [called_functions] => Array ( [a] => Array ( [memory_size] => 4 [blocks_count] => 1 [memory_size_inclusive] => 10485825 [blocks_count_inclusive] => 5 [calls] => 1 [called_functions] => Array ( [b] => Array ( [memory_size] => 10485821 [blocks_count] => 4 [memory_size_inclusive] => 10485821 [blocks_count_inclusive] => 4 [calls] => 1 [called_functions] => Array ( [str_repeat] => Array ( [memory_size] => 0 [blocks_count] => 0 [memory_size_inclusive] => 0 [blocks_count_inclusive] => 0 [calls] => 1 [called_functions] => Array ( ) ) ) ) ) ) [memprof_dump_array] => Array ( [memory_size] => 0 [blocks_count] => 0 [memory_size_inclusive] => 0 [blocks_count_inclusive] => 0 [calls] => 1 [called_functions] => Array ( ) ) ) ) ) )
Возвращает версию расширения в виде строки. Версию можно сравнить с помощью version_compare().
Расширения могут конфликтовать с xdebug, blackfire или другими расширениями. Если это так, пожалуйста, сообщите об этом.
Текущая ветка поддерживает версии от PHP 7.1 до PHP 8.
Ветка php5 поддерживает PHP 5.
См. INTERNALS.md