PHP Fatal Error: Allowed Memory Size — ломаем мифы и настраиваем

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

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

Начать курс

Вступление: почему ваш PHP-скрипт «взрывается»?

Вы когда-нибудь видели на экране белое полотно с леденящей душу надписью «Fatal Error: Allowed Memory Size of 134217728 Bytes Exhausted»? Если да — вы не одиноки. Этот вопрос на Stack Overflow собрал тысячи просмотров, и каждый второй PHP-разработчик хотя бы раз в жизни с ним сталкивался.

Цифра 134217728 байт — это ровно 128 мегабайт (стандартный лимит для многих хостингов). Когда ваш скрипт пытается занять больше — PHP говорит «стоп» и выбрасывает фатальную ошибку. Но не спешите паниковать! В этой статье мы разберём, почему это происходит, как исправить и — самое главное — как оптимизировать производительность, чтобы ошибка памяти больше вас не тревожила.

Статья написана для образовательного сайта PythonLib, но весь код и примеры — на PHP. Поехали!

Что такое memory_limit и откуда берётся «134217728»?

В PHP есть директива memory_limit, которая устанавливает максимальный объём памяти, доступный одному скрипту. По умолчанию во многих конфигурациях (особенно на shared-хостингах) стоит значение 128M (или 134217728 байт).

Проверить текущий лимит можно так:

<?php
echo ini_get('memory_limit'); // Выведет, например, "128M"
?>

Когда ваш скрипт превышает этот лимит — PHP немедленно завершает выполнение с фатальной ошибкой. Причины могут быть разными: от неоптимального кода до загрузки гигантских файлов в память.

Типичные сценарии, вызывающие ошибку

  • Работа с большими массивами — например, чтение CSV-файла целиком в память.
  • Циклы с утечками — забыли освободить переменные или используете глобальные массивы.
  • Библиотеки для обработки изображений — GD или Imagick при работе с фото высокого разрешения.
  • Рекурсивные функции — без базового условия уходят в бесконечность и съедают стек.
  • ORM и кэширование — некоторые ORM (например, Doctrine) могут загружать всю таблицу в память.

Как исправить ошибку: 3 проверенных способа

1. Временное увеличение лимита через ini_set()

Самый быстрый способ — прямо в скрипте увеличить лимит:

<?php
ini_set('memory_limit', '256M');
// Теперь скрипт может использовать до 256 MB
?>

Важно: это сработает только если ваш хостинг разрешает переопределение директивы. На некоторых хостингах ini_set() для memory_limit заблокирован.

2. Изменение php.ini или .htaccess

Если у вас есть доступ к серверу, отредактируйте php.ini:

memory_limit = 256M

Или через .htaccess (на Apache):

php_value memory_limit 256M

После изменений перезапустите веб-сервер или PHP-FPM.

3. Оптимизация кода — лучший способ

Увеличить лимит — это костыль. Настоящее решение — написать эффективный код. Давайте разберём примеры.

Реальный пример: обработка большого CSV-файла

Допустим, у вас есть CSV-файл на 500 000 строк. Наивный код может выглядеть так:

<?php
$rows = file('data.csv'); // Загружает ВЕСЬ файл в память!
foreach ($rows as $row) {
    // обработка
}
?>

При размере файла 200 MB — скрипт упадёт с ошибкой памяти.

Оптимизация: построчное чтение

<?php
$handle = fopen('data.csv', 'r');
if ($handle) {
    while (($row = fgetcsv($handle)) !== false) {
        // обрабатываем одну строку за раз
        // память почти не растёт
    }
    fclose($handle);
}
?>

Теперь скрипт использует всего несколько мегабайт, независимо от размера файла.

Профилирование памяти: находим «прожорливые» участки

Чтобы понять, где именно тратится память, используйте встроенные функции PHP:

  • memory_get_usage() — текущее потребление памяти.
  • memory_get_peak_usage() — пиковое потребление за время работы скрипта.

Пример профилирования:

<?php
echo "Начало: " . memory_get_usage() . " bytes\n";

$bigArray = range(1, 100000);
echo "После создания массива: " . memory_get_usage() . " bytes\n";

unset($bigArray);
echo "После очистки: " . memory_get_usage() . " bytes\n";

echo "Пик: " . memory_get_peak_usage() . " bytes\n";
?>

Вывод поможет увидеть, какие операции «съедают» память. Если пик близок к лимиту — ищите утечки или неоптимальные структуры данных.

Использование Xdebug для глубокого анализа

Для серьёзного профилирования установите Xdebug и включите xdebug.mode=profile. Тогда вы получите детальный отчёт в виде flame graph, где видно, сколько памяти и времени тратит каждая функция.

Типичные ошибки и их решения

Ошибка: загрузка изображений через GD

При работе с фото 6000x4000 пикселей библиотека GD может запросить десятки мегабайт. Решение — уменьшать разрешение или использовать Imagick с оптимизацией.

<?php
// Плохо
$img = imagecreatefromjpeg('large.jpg');

// Хорошо — сразу уменьшаем
$src = imagecreatefromjpeg('large.jpg');
$dst = imagecreatetruecolor(800, 600);
imagecopyresampled($dst, $src, 0, 0, 0, 0, 800, 600, imagesx($src), imagesy($src));
imagedestroy($src); // освобождаем исходник
?>

Ошибка: рекурсия без ограничения

<?php
function recursive($n) {
    if ($n <= 0) return;
    recursive($n - 1);
}
recursive(100000); // Fatal Error! Стек переполнен
?>

Решение — увеличить xdebug.max_nesting_level или переписать алгоритм итеративно.

Продвинутые техники оптимизации

1. Использование генераторов (yield)

Генераторы позволя

Блоги

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