Как отследить потери памяти?

ilyichzc

Новичок
Как отследить потери памяти?

Написал демон-сервер на PHP.
Программа работает и с назначением справляется, но есть проблема: Очень быстро кушает свободную память. Причем даже когда к серверу небыло ни одного подключения. Тоесть память поедается в основном цикле. Но вот куда она уходит пока найти не смог. Уже отключил логирование и прочие примочки и все равно.. За час уплывает примерно 10 мегов.
Ко всему, с ростом памяти увеличивается и задержка на цикл в миллисекундах. Тоесть начинает тормозить и с каждым разом больше и больше. Хотя возможно тормоза это отдельная проблема и с ростом потребления памяти не связана.

Программа работает из командной строки.
Посоветуйте какой-нибудь удобный и быстрый способ найти утечку, а то у самого опыта в этом деле явно не достаточно.
Заранее благодарен.
 

ilyichzc

Новичок
memory_get_usage и так пользую.
По ней в принципе и вижу тенденции к росту.
А вот как определить в какой части кода кроме как ручками, что пока и делаю ...
 

Alexandre

PHPПенсионер
damngood ну и твои предложения, как отлаживать?

у меня кушал память XCache+php-fpm,
запустить memtruck не получилось,

в результате пришлось написать чекер, который определял когда память не залезала в своп (или чуть раньше, например при достижении 800Мег на самый жирный процесс ) и потом мягко перезапускал РНР.
 

damngood

Мозг был, но ушел...
Alexandre
ставить в самых подозреваемых тобой местах вывод потребления памяти, имхо. Твои предложения?
 

Alexandre

PHPПенсионер
у меня еще в демониальных скриптах сделан само-контроль памяти:
- на каждой итерации проверяется memory_get_usage(),
- как только получаемое значение превысит некую константу ( на моем сервере это 150М ), то скрипт перезапускается.
 

ilyichzc

Новичок
Отладка то хорошо, но я не знаю отладчиков для проги, запущенной из командной строки, а не в среде разработки. По этому и написал на форум. А трейсить объем памяти из разных "подозреваемых" процедур - конечно можно, но это не гарантирует точности и довольно трудоемко т.к. во многих методах выход происходит в разных частях кода. Соответственно нужно вставлять вывод в нескольких местах. Вобщем удобней если ест ькакой то софт, который висит над PHP и симафорит каким объектом или методом память захапана. В принципе я про такое и спрашивал.

-~{}~ 13.01.10 16:29:

Автор оригинала: Alexandre
у меня еще в демониальных скриптах сделан само-контроль памяти:
- на каждой итерации проверяется memory_get_usage(),
- как только получаемое значение превысит некую константу ( на моем сервере это 150М ), то скрипт перезапускается.
Интересно. Мне такой вариант тоже реализовать нужно. А как ты перезапуск скрипта делаешь если не секрет?
Освобождаешь слушающий сокет и запускаешь exec? Я просто пока других вариантов не вижу. А в таком случае система может порт не успеть освободить, на сколько я знаю.
 

Alexandre

PHPПенсионер
наврядли, не встречал такого)
вполне реальная ситуация.
если ты в цикле не используешь типа какого: $str .= $str .'bla-bla-bla'; или сумашедшей рекурсии, то утечек в принципе быть не должно. Текут, как правило, кривые сторонние либы.
как я упомянул выше, в моем случае это был XCache.
 

ilyichzc

Новичок
Не, я все сам писал и пока там либов никаких нет. Свои видимо кривые. Я вроде бы нашел проблемное место. Перезапустил и больше тьфу тьфу вроде не растет. А то прямо думал аномалия какая то. Но все же время покажет.

Есть еще одна непонятная мне вещь:

Сервер может писать лог в файл.
Под виндой лог пишется нормально, а на хостинге под CentOS файл пишется как я понял только до смены суток. Тоесть на следующий день записей новых в файле уже нет. Вот думаю, в чем может быть дело. В никсах я совсем не спец. Процесс после запуска демонизируется и в топе висит от nobody. Но файл лога создается после демонизации и по началу нормальн о заполняется. Размер файла вполне умеренный.
 

Alexandre

PHPПенсионер
А как ты перезапуск скрипта делаешь если не секрет?
у меня не сервер, перезапускал этим http://code.google.com/p/php-forker/

еще как вариант можно system( /usr/bin/php /pat/to/script.php > /dev/null 2> /dev/null & );
но в этом случае порождаются зомби процессы.

в твоем случае - сокеты надо закрывать и перезапускать сервер.
А в таком случае система может порт не успеть освободить, на сколько я знаю
надо тестировать.
если перезапуск будет производиться пару раз в день - это не страшно.

-~{}~ 13.01.10 16:40:

а на хостинге под CentOS файл пишется как я понял только до смены суток.
надо открыть файл, сделать запись и закрыть
поставить флаг - создать если не существует.

в случае ротации логов, у тебя информация сохранится.
 

ilyichzc

Новичок
А на сколько такой подход мдленней, чем писать все время в открытый файл? В принципе можно при ошибке записи его переоткрывать поновой..

-~{}~ 13.01.10 16:48:

Да, забыл добавить, что у меня предусмотрена ротация по суткам и по объему файла. Тоесть при смене суток файл закрывается и создается новый. ТОже при достижении определенного объема. На хостинге новый файл попросту не создается.
 

Alexandre

PHPПенсионер
А на сколько такой подход мдленней, чем писать все время в открытый файл? В принципе можно при ошибке записи его переоткрывать поновой.
в зависимости от того, что и как логгировать. если до 100 запросов в сек - то и переоткрывание не повредит быстродействию и не будет утери информации при смене файла.

При переименовании файла, Ось начинает писать в новый физический файл, только в случае, если все дескрипторы на этот файл будут закрыты. я делал эксперимент: скрипт непрерывно писал в лог лимон записей, в это время я переименовывал файл. сумма записей в обоих кусках была равна заданной.


в случае очень интенсивного логгирования, надо придумать поблочное логгирование (буферизацию). Накапливаем лог в памяти и потом его скидываем в файл.
 

Активист

Активист
Команда форума
а чем echo и STDOUT, STDERR не устраивает в консольном приложении?

/usr/bin/php /pat/to/script.php >> /path/to/log 2>> &1 &

И ротировать через крон, например...

Ну а в случае с велосипедом? Чем syslog не устраивает? [m]syslog[/m]
 

MiksIr

miksir@home:~$
Если пишет активно, то переоткрывать нужно по-сигналу.
http://ru.php.net/manual/en/function.pcntl-signal.php
Делаешь ротацию и шлешь сигнал. logrotate это умеет.
По сигналу закрываешь старый дескриптор и открываешь новый.

Alexandre а вот не дай бог несколько процессов пишут в лог... это ж какая каша будет, если самому буферизировать =)

-~{}~ 13.01.10 19:12:

Активист, а будет ли ротироватся то? =)

-~{}~ 13.01.10 19:14:

А вообще +1 за сислог... если, конечно, у вас не "nginx на php" =)
 

Alexandre

PHPПенсионер
Alexandre а вот не дай бог несколько процессов пишут в лог... это ж какая каша будет, если самому буферизировать =)
писать в лог должен мастер-процесс, я так понимаю...Или по крайней мере, заниматься буферизацией.
Например, nginx построен именно таким образом.

но, я не уверен, что именно в данном демоне нужна буферизация. Ход мыслей следующий: раз демон написан на пхп, значить он держит не большую нагрузку, раз нагрузка не большая, значить у нас случай преждевременной оптимизации.
 
Сверху