«Allowed Memory Size of 134217728 Bytes Exhausted» — стоп-кран вашего PHP-приложения
Вы когда-нибудь видели это сообщение посреди ночи, когда сайт неожиданно падает, а в логах — белая надпись на чёрном фоне? Если да — вы не одиноки. Тысячи разработчиков на Stack Overflow задавались вопросом, почему их, казалось бы, безобидный PHP-скрипт внезапно «съедает» все 128 мегабайт оперативной памяти и вылетает с фатальной ошибкой.
Давайте разберёмся, что на самом деле означает эта ошибка, почему она возникает и, главное, как её исправить раз и навсегда. Мы не просто увеличим лимит памяти — мы научимся писать код, который не жрёт ресурсы как голодный студент в столовой.
Что означает «134217728 Bytes Exhausted»?
Число 134 217 728 — это 128 мегабайт. Именно столько памяти PHP разрешено использовать вашему скрипту по умолчанию. Когда скрипт пытается выделить больше — бах! — и вы получаете Fatal Error. Это защитный механизм, который не даёт одному скрипту убить весь сервер.
Но вот в чём подвох: 128 МБ — это очень мало для современных приложений. Обработка большого XML-файла, генерация отчёта из базы данных, работа с изображениями или тяжелыми библиотеками — всё это может легко превысить лимит.
Почему это происходит? Три главные причины
- Жадные циклы и рекурсия — когда вы загружаете в память все данные сразу, вместо того чтобы обрабатывать их порциями.
- Утечки памяти — статичные переменные, глобальные массивы и неправильное использование
staticмогут накапливать данные. - Тяжёлые библиотеки и расширения — например, обработка изображений через GD или работа с PDF.
Как исправить ошибку: от простого к сложному
Способ 1: Увеличить лимит памяти (быстрое решение)
Самый очевидный путь — просто дать PHP больше памяти. Но помните: это не лечение, а обезболивающее. Если ваш код плохо написан, он съест и 512 МБ, и 1 ГБ.
Есть три способа увеличить лимит:
1. В файле php.ini (постоянное изменение):
memory_limit = 256M
2. В .htaccess (если доступен):
php_value memory_limit 256M
3. В самом скрипте (только для текущего выполнения):
ini_set('memory_limit', '256M');
Но предупреждаем: если вы на shared-хостинге, хост может не разрешить увеличить лимит выше определённого порога. И даже если разрешит — не злоупотребляйте.
Способ 2: Оптимизация кода — настоящее решение
Вместо того чтобы давать скрипту больше памяти, давайте научим его использовать то, что есть, с умом.
Используйте unset() для освобождения памяти
PHP — не C++, но ручное управление памятью всё ещё работает. Когда большая переменная больше не нужна — удалите её:
$data = file_get_contents('huge_file.csv');
// обрабатываем данные
processData($data);
// освобождаем память
unset($data);
Обрабатывайте данные по частям
Вместо того чтобы загружать в память 100 000 строк из базы, используйте курсоры или лимиты:
// ПЛОХО: загружаем всё в память
$users = $db->query("SELECT * FROM users")->fetchAll();
// ХОРОШО: обрабатываем по одной строке
$stmt = $db->query("SELECT * FROM users");
while ($row = $stmt->fetch()) {
processUser($row);
// PHP сам освободит память после каждой итерации
}
Используйте генераторы (yield)
Генераторы — это магия для работы с большими наборами данных. Они не хранят все значения в памяти:
function getLargeData() {
for ($i = 0; $i < 1000000; $i++) {
yield $i;
}
}
foreach (getLargeData() as $value) {
// обрабатываем по одному элементу
echo $value . "\n";
}
В этом примере мы не создаём массив на миллион элементов — мы генерируем их на лету.
Способ 3: Профилирование — найдите виновника
Иногда непонятно, какой именно участок кода жрёт память. Используйте встроенные функции PHP:
echo "Память до: " . memory_get_usage() . " байт\n";
// ваш код
echo "Память после: " . memory_get_usage() . " байт\n";
echo "Пиковое использование: " . memory_get_peak_usage() . " байт\n";
Если вы видите, что пиковое использование постоянно приближается к лимиту — ищите проблему в циклах, рекурсии или больших массивах.
Реальный пример: обработка CSV-файла на 500 МБ
Представьте, что вам нужно обработать CSV-файл размером 500 МБ. Наивный подход — загрузить его целиком в память:
// ПЛОХО: упадёт на любом сервере
$lines = file('huge_file.csv');
foreach ($lines as $line) {
// обработка
}
Этот код сразу вызовет Allowed Memory Size Exhausted, потому что file() загружает весь файл в массив. Правильное решение — читать построчно:
// ХОРОШО: читаем построчно
$handle = fopen('huge_file.csv', 'r');
if ($handle) {
while (($line = fgets($handle)) !== false) {
// обрабатываем одну строку
processLine($line);
}
fclose($handle);
}
В этом случае в памяти находится только одна строка за раз. Разница между 500 МБ и несколькими килобайтами!
Когда увеличение лимита — это нормально
Бывают ситуации, когда код написан оптимально, но 128 МБ действительно мало. Например:
- Работа с большими изображениями (GD, Imagick)
- Генерация PDF-документов
- Кэширование в памяти (Redis не всегда доступен)
- Использование тяжёлых фреймворков (Symfony, Laravel) с большими запросами
В таких случаях разумно увеличить лимит до 256 МБ или 512 МБ. Но не до бесконечности — помните, что PHP-скрипт работает в рамках одного процесса, и если вы дадите ему 2 ГБ, а скрипт их съест — сервер может лечь.