Allowed memory size exhausted - причины по убыванию частоты
Страница, обмен или консольный скрипт обрывается сообщением об исчерпанной памяти. Разбираем причины по убыванию частоты.
Как проверить
Смотрим, какой лимит действует на самом деле:
php -i | grep memory_limit # лимит консольного PHPgrep -rn "memory_limit" /etc/php*/ .htaccess bitrix/.settings.php 2>/dev/null# консоль, веб-сервер и админка нередко работают с разными значениями# .htaccess на связке nginx с php-fpm не действует вовсе: правку там не увидятЛимит бывает задан в четырёх местах сразу, и действует не тот, который правили
последним. Веб-запрос читает настройку своего пула, консоль - свой файл
настроек, а .htaccess на связке nginx с процессами PHP не действует вовсе.
Читаем сообщение целиком, а не первую строку:
grep -i "allowed memory size" /var/log/php-fpm/error.log | tail -3# tried to allocate 131426964488 bytes - это не нехватка памяти, а сломанные данныеgrep -c "allowed memory" /var/log/php-fpm/error.log # одиночный случай или потокВ сообщении две цифры: предел и запрошенный объём. Запрос в несколько мегабайт означает, что памяти действительно не хватило, а запрос в гигабайты - что код считает длину по испорченному значению или ушёл в рекурсию.
Замеряем пик в подозрительном месте:
echo round(memory_get_peak_usage(true) / 1048576, 1), " МБ\n";// ставят до и после тяжёлого участка: разница и есть цена этого куска кодаecho round(memory_get_usage(true) / 1048576, 1), " МБ сейчас\n"; // текущий расходПик показывает не общий расход, а самую высокую точку. Две отметки вокруг подозрительного цикла отвечают на вопрос точнее, чем любые рассуждения о прожорливости платформы.
Заменяем выборку целиком на порции:
$rs = CIBlockElement::GetList([], $filter, false, ['nTopCount' => 500], $select);while ($row = $rs->Fetch()) { /* обрабатываем и сразу пишем результат */ }$count = CIBlockElement::GetList([], $filter, []); // количество без выборки// накапливать результат в массиве нельзя: он и съедает всю памятьunset($row); // в длинном цикле чистят и накопителиПодсчёт записей через их полную выборку - самая частая ошибка в скриптах. Количество платформа отдаёт отдельным вызовом, а обработку строят так, чтобы в памяти одновременно жила одна порция, а не весь инфоблок.
Причины
-
Скрипт держит в памяти всю выборку примерно 35% случаев
ПризнакПадает свой скрипт, обмен или массовая правка, причём тем раньше, чем больше данных.
ПроверкаСмотрим, есть ли в коде выборка без ограничения и накопление результата в массиве.
Что делатьПереписываем на порции с сохранением результата сразу, а количество записей берём отдельным запросом.
-
Лимит поднят не в том месте примерно 25% случаев
ПризнакПамять увеличили, перезапустили сервер, а в сообщении стоит прежнее значение предела.
ПроверкаСравниваем предел из сообщения с настройками пула процессов, консоли и файла настроек платформы.
Что делатьПравим настройку там, где выполняется упавший код, и проверяем результат выводом сведений о среде.
-
Тяжёлая операция платформы примерно 20% случаев
ПризнакПадает восстановление из копии, установка обновления, обмен с учётной системой или страница админки.
ПроверкаПроверяем размер обрабатываемых данных: части архива, объём выгрузки, число элементов на странице списка.
Что делатьПоднимаем предел для конкретной операции и уменьшаем порцию: размер части архива, шаг обмена, число строк в списке.
-
Зацикливание или испорченные данные примерно 12% случаев
ПризнакВ сообщении запрошены гигабайты, а падение происходит мгновенно и всегда на одном месте.
ПроверкаЧитаем трассировку: рекурсивный вызов виден по повторяющимся строкам одного и того же файла.
Что делатьЧиним данные или логику; поднимать предел здесь бесполезно, память кончится при любом значении.
-
Утечка в длинном цикле примерно 8% случаев
ПризнакСкрипт работает минутами и падает не сразу, а после нескольких тысяч итераций.
ПроверкаПечатаем пик памяти каждые сто шагов: у утечки он растёт равномерно и не возвращается.
Что делатьОчищаем накопители внутри цикла, отключаем сбор запросов на отладку и не копим вывод в переменной.
Если ничего не помогло
Смотрим, где именно оборвался код. Сообщение называет файл и строку, и если это файл платформы, виноват почти всегда не он, а данные или свой обработчик, который его вызвал.
Запускаем ту же работу в консоли. Консольный запуск не ограничен временем веб-сервера и показывает ошибку целиком, вместе с трассировкой, а не белым экраном.
Проверяем правила корзины и скидки на больших заказах. Условия скидок платформа разбирает на лету, и заказ на сотни позиций с десятком правил - известное тяжёлое место модуля продаж.
Частые вопросы
Поднял memory_limit, а ошибка осталась с прежним пределом.
Значение правили не там, где выполняется код: у процессов веб-сервера, консоли и планировщика настройки разные. Предел из текста ошибки сравнивают с настройкой конкретного окружения, а не с той, которую редактировали.
Сколько памяти нужно сайту на платформе?
Обычной странице хватает 256 мегабайт, тяжёлым операциям - от 512. Постоянная потребность в большем значении означает не требовательность платформы, а выборку без ограничения где-то в своём коде.
Скрипт просит выделить гигабайты - что это значит?
Это не нехватка памяти, а сломанная логика: рекурсия или расчёт длины по испорченному значению. Увеличение предела в таком случае не помогает никогда.
Обмен с учётной системой падает на большом каталоге.
Уменьшают шаг обмена и число элементов в одной части выгрузки, а предел памяти поднимают только для точки обмена. Обмен целиком в одну итерацию не выполняют даже на маленьком каталоге.
Как найти прожорливый участок в своём коде?
Расставить замеры пика памяти вокруг подозрительных участков и сравнить разницу. Профилировщик покажет точнее, но две строки с выводом пика обычно закрывают вопрос быстрее.
Смежное
- Ошибки сервера - оглавление подтемы
- Белая страница вместо сайта: разбор причин - когда та же нехватка проходит молча
- Ошибки 500 и 502: где искать причину и чем они отличаются - как выглядит то же падение снаружи
- Массовая правка товаров: обновление свойств скриптом - обход больших объёмов порциями
- Выгрузка в Excel из кода: библиотека, объём, отдача файла - частый источник падения по памяти
- Долгий обмен с 1С: шаг, порции, таймауты - та же беда при выгрузке каталога
- Отладка на боевом сайте: журналы, режим ошибок, поиск виновника - где читать трассировку
- Инфраструктура - устройство сервера и окружения