Web

Как снять ограничение на использование памяти для PHP-скрипта

Ситуация

У меня проблема с 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

Определение размера удаленного файла без загрузки файла

Web

Как настроить права доступа к файлам в Laravel?

Workplace Facebook: что это за платформа и как ей пользоваться?
Web

Workplace Facebook: что это за платформа и как ей пользоваться?

Web

В чем разница между require, include, require_once и include_once?

×