Почему PHP-скрипт «съедает» 128 МБ и как с этим бороться

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

«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 ГБ, а скрипт их съест — сервер может лечь.

Типичные ошибки новичков

Блоги

Рекомендаций по книгам