Ситуация
У меня проблема с PHP-скриптом, который получает следующее сообщение об ошибке:
Fatal error: Out of memory (allocated 359923712) (tried to allocate 72 bytes) in /path/to/piwik/core/DataTable.php on line 969
Скрипт, который я запускаю:
/path/to/piwik/misc/cron/archive.sh
Я предполагаю, что цифры — это байты, что означает, что общее количество составляет приблизительно 360 МБ.
Для всех целей я увеличил лимит памяти на сервере намного выше 360 МБ, но именно на этом значении (плюс-минус некоторое количество байт) он постоянно выдает ошибку.
Обратите внимание: этот вопрос не об устранении утечки памяти в скрипте, и не о том, почему сам скрипт использует так много памяти. Скрипт является частью процесса архивирования «Piwik», поэтому я не могу просто исправить утечку памяти и т. д.
Вопрос
Учитывая, что скрипт пытается использовать более 360 МБ памяти, что я не могу изменить, почему мне кажется невозможным увеличить количество памяти, доступной для php на моем сервере?
Что я пробовал
Увеличивал лимит памяти PHP в файле php.ini:
php -i | grep php.ini
Путь к файлу конфигурации (php.ini) => /usr/local/lib
Загружал файл конфигурации => /usr/local/lib/php.ini
Я отредактировал этот файл, так что директива memory_limit стала выглядеть следующим образом;
memory_limit = -1
Перезапускал Apache и проверял, что новое значение закрепилось:
$ php -i | grep memory_limit
memory_limit => -1 => -1
Запускал скрипт и получал ту же ошибку.
Я также пробовал 1G, 768M и т.д., все с тем же результатом (т. е. без изменений).
Снимал ограничения памяти для дочерних процессов Apache.
Я нашел и отредактировал файл httpd.conf, чтобы убедиться, что там нет директивы RLimitMEM.
Затем я использовал WHM's Apache Configuration > Memory Usage Restrictions для создания ограничения, которое, по его утверждению, было на уровне 1000M (и было подтверждено проверкой httpd.conf).
Оба этих способа не привели к изменениям в скрипте, ошибающемся на 360 МБ.
Увеличивал ограничение памяти для каждого процесса в Linux.
Текущие ограничения, установленные в системе:
$ ulimit -m
524288
$ ulimit -v
524288
Я попытался установить оба лимита на неограниченный:
$ ulimit -m unlimited
$ ulimit -v unlimited
$ ulimit -m
unlimited
$ ulimit -v
unlimited
И снова это не привело ни к какому решению моей проблемы.
Я также столкнулся со смежной проблемой. Если я устанавливаю ulimit -v 1024000, а затем проверяю его с помощью ulimit -v, я получаю правильное значение "1024000". Если я запущу сценарий снова, он работает намного дольше, но в конце концов выдаст ошибку с тем же пределом памяти, который был достигнут. Если я немедленно проверю ulimit -v, то он вернется к исходному значению «524288». Похоже, что это и есть первопричина проблемы.
Ответ 1
Я взял текущую версию Piwik -- В версии 1.5 строка 969 выглядит следующим образом:
public function addRowsFromSerializedArray( $stringSerialized ) {
$serialized = unserialize($stringSerialized);
if($serialized === false) {
throw new Exception("Ошибка десериализации!");
}
$this->addRowsFromArray($serialized);
}
и конкретно $serialized = unserialize($stringSerialized);. Вызов unserialize может занимать невероятно много памяти.
Как вы отметили, это явно не ошибка в вашем скрипте и является ошибкой – нехватка памяти.
Предложение: В конфигурационном файле:
/.../piwik/config/global.ini.php
Возможно, вам нужно увеличить один из этих лимитов:
# во время архивирования Piwik ограничивает количество записанных результатов по соображениям производительности.
# максимальное количество строк для любой из таблиц Referers (ключевые слова, поисковые системы, кампании и т. д.)
# это ограничение также будет применяться к отчетам об именах и значениях пользовательских переменных
datatable_archiving_maximum_rows_referers = 1000
# максимальное количество строк для любой из подтаблиц Referers (поисковые системы по ключевому слову, ключевое слово по кампании и т .д.)
datatable_archiving_maximum_rows_subtable_referers = 50
# максимальное количество строк для любой из таблиц «Действия» (страницы, загрузки, ссылки)
datatable_archiving_maximum_rows_actions = 500
# максимальное количество строк для страниц в категориях (подстраницы, при нажатии на + для категории страницы)
# примечание: не должно превышать лимит отображения в Piwik_Actions_Controller::ACTIONS_REPORT_ROWS_DISPLAY
# потому что каждый подкаталог не имеет пагинации внизу, поэтому все данные должны быть отображены, если это возможно
datatable_archiving_maximum_rows_subtable_actions = 100
# максимальное количество строк для других таблиц (Провайдеры, конфигурации настроек пользователя)
datatable_archiving_maximum_rows_standard = 500
где я заменил полуколонки на знаки «#» только для того, чтобы сделать автоколор sf читаемым
Вы также можете попробовать добавить:
CMD_TO_CHECK_SETTINGS="$PHP_BIN -i > /tmp/piwik-php-env.out"
$CMD_TO_CHECK_SETTINGS
в archive.sh, чтобы определить, есть ли другие настройки, которые отменяют настройки в файле php.ini.
Ответ 2
Существует ограничение на размер выполняемой SQL-команды, которое по умолчанию составляет всего 1 МБ. Чтобы увеличить ограничение на размер в MySQL, отредактируйте /etc/my.cnf и установите max_allowed_packet=32M
Убедитесь, что лимит памяти PHP установлен достаточно высоким для каждого процесса, отредактировав /usr/local/lib/php.ini и установив memory_limit = 512M.
Наконец, убедитесь, что все процессы имеют жесткий лимит не менее 1Гб, прежде чем система отключит их, выполнив ulimit -v 1048576 в командной строке.
ulimit -v 1048576 повысит только внутренний лимит. Если жесткий предел недостаточно высок, система автоматически сбросит внутренний предел до общего на процесс.
Чтобы установить общий предел, добавьте переключатель -H:
ulimit -vH 1048576
а затем увеличьте внутренний предел до этого значения:
ulimit -vS 1048576
Ответ 3
Можете ли вы подтвердить, в каком файле конфигурации вы изменили ограничения памяти? Обратите внимание, что есть два разных конфига: один для PHP, выполняемого через веб-сервер, а второй для PHP, выполняемого через CLI.
~$ ls /etc/php5/
apache2 cli conf.d
~$ ls /etc/php5/apache2/
conf.d php.ini
~$ ls /etc/php5/cli/
conf.d php.ini
Также, если это выполняется через браузер, в той же директории, где находится сам скрипт, создайте файл temp.php со следующим содержимым:
<?php phpinfo(); ?>
Проверьте, как отображается значение memory_limit при переходе к этому файлу.
Ответ 4
Это определенно ошибка скрипта. Похоже, что существует утечка памяти, поэтому независимо от того, насколько вы увеличили лимит памяти в PHP, он будет превышен.
Я использую Piwik на базовом уровне и не помню, чтобы когда-либо использовал скрипт архивации напрямую. Piwik все еще немного глючит, но последняя версия 1.4 кажется гораздо менее глючной, чем предыдущие. Я не рекомендую возиться с настройками системы или PHP ради того, чтобы бесконечно запускать ошибочный скрипт. Лучше обратиться на форум поддержки piwik.
Web