Конфигурация memory_limit в PHP
Настройка memory_limit в PHP
Как установить лимит памяти глобально для всех скриптов?
Основной способ: редактирование файла php.ini
Этот метод подходит для серверов, где есть доступ к главному конфигурационному файлу PHP. Изменение в php.ini влияет на все скрипты, запускаемые на сервере, включая CLI и веб-режимы.
; Пример строки в php.ini
memory_limit = 256MPhp ubuntu (php на ubuntu)
Шаги:
- Найти файл php.ini. Обычно он расположен в /etc/php/8.x/apache2/php.ini (Linux) или C:\php\php.ini (Windows). Точный путь можно узнать через
php --iniилиphpinfo(). - Открыть файл с правами администратора.
- Найти строку
memory_limitи изменить значение. Если строки нет, добавить её. - Сохранить изменения и перезапустить веб-сервер (например,
sudo systemctl restart apache2).
Типичные проблемы:
- После изменения не перезагружен веб-сервер или PHP-FPM - изменения не вступают в силу. Необходим перезапуск.
- Неправильный синтаксис: вместо
memory_limit = 256Mнаписаноmemory_limit=256M(без пробела) - это может вызвать ошибку при загрузке конфигурации. - Значение слишком большое для физической памяти сервера - скрипты могут вызывать сбои системы или out-of-memory.
- Отсутствие прав на запись в php.ini - требуется сменить владельца или использовать sudo.
Как изменить memory_limit для конкретного сайта при отсутствии доступа к php.ini?
Использование файла .htaccess (для Apache)
Когда у пользователя нет доступа к глобальному php.ini, но сервер использует Apache с mod_php, можно задать настройки через .htaccess. Это удобно для shared-хостинга.
# В корневом .htaccess
php_value memory_limit 128M
php_value max_execution_time 300Localhost php (настройка локального сервера php)
Важно: директива php_value работает только если сервер не использует PHP-FPM или CGI. Для последних потребуется другой подход.
Проблемы и ограничения:
- Директива может быть запрещена в настройках Apache (
AllowOverride None). В этом случае изменения проигнорируются. - Для PHP-FPM .htaccess не работает - нужно настраивать пул через pool.d.
- Значение применяется только для файлов в этом каталоге и его подкаталогах.
Как временно увеличить память для конкретного скрипта?
Использование функции ini_set()
Если нужно изменить лимит памяти только для одного скрипта или части скрипта, используется встроенная функция ini_set(). Изменение действует только на текущий запрос и не влияет на другие процессы.
<?
// Установка лимита памяти для данного скрипта
ini_set('memory_limit', '512M');
// Теперь скрипт может использовать до 512 МБ
$data = str_repeat('x', 500 * 1024 * 1024); // выделение 500 МБ
?>
Php windows (php на windows)
Ограничение: функция не сработает, если в php.ini установлен disable_functions или если скрипт уже превышает новый лимит до вызова ini_set.
Типичные ошибки:
ini_set()не может уменьшить лимит, если он уже установлен на более высокое значение другим методом.- Попытка установить значение ниже используемой памяти приведет к фатальной ошибке.
- Если
memory_limitотключен в глобальных настройках (значение -1), ini_set не сможет его изменить в некоторых режимах.
Как запустить скрипт с особым лимитом памяти из командной строки?
Использование опции -d при запуске php
Для CLI-скриптов можно задать параметр прямо в команде без изменения конфигурационных файлов. Это полезно для одноразовых задач, крона или тестирования.
php -d memory_limit=1024M my_script.phpAdmin php (администрирование php)
Параметр -d определяет значение на время выполнения только этого скрипта. Можно комбинировать с другими директивами.
Проблемы:
- Не работает для веб-запросов, только для CLI.
- Если скрипт требует прав на редактирование php.ini, данный метод не подойдет.
- Значение в команде имеет приоритет над php.ini, но не над ini_set() внутри скрипта.
Как узнать текущее значение memory_limit и объем используемой памяти?
Проверка и мониторинг
Для отладки и контроля потребления памяти полезно использовать функции ini_get(), memory_get_usage() и memory_get_peak_usage().
<?
echo 'Текущий лимит: ' . ini_get('memory_limit') . "\n";
echo 'Использовано памяти: ' . memory_get_usage() / 1024 / 1024 . ' МБ' . "\n";
echo 'Пиковое использование: ' . memory_get_peak_usage() / 1024 / 1024 . ' МБ' . "\n";
?>
Типичные ошибки при интерпретации:
memory_get_usage()возвращает память, выделенную самому PHP, а не всей системе. Для оценки полной нагрузки нужно учитывать и другие процессы.- Значение в php.ini может быть задано в разных единицах (K, M, G) - функция ini_get возвращает строку, ее нужно преобразовывать.
- При использовании phpinfo() нужно искать не только memory_limit, но и другие настройки, влияющие на потребление.
Расширенные примеры настройки и диагностики memory_limit
Пример 1: Изменение лимита внутри скрипта с проверкой
Скрипт демонстрирует вызов ini_set и проверку, удалось ли применить новое значение. Это полезно, когда не уверены, разрешено ли изменять директиву.
<?
// Пример 1: установка и проверка изменения memory_limit
echo "Начальный лимит: " . ini_get('memory_limit') . "\n";
$result = ini_set('memory_limit', '256M');
if ($result === false) {
echo "Ошибка: не удалось изменить memory_limit\n";
} else {
echo "Новый лимит: " . ini_get('memory_limit') . "\n";
}
?>
Начальный лимит: 128M Новый лимит: 256M
Пример 2: Обработка ошибки исчерпания памяти и конвертация единиц
Показывает, как перехватить фатальную ошибку при превышении лимита и как преобразовать строковое значение memory_limit в байты для анализа.
<?
// Пример 2: перехват ошибки превышения памяти
try {
$data = str_repeat('x', 2000 * 1024 * 1024); // 2 ГБ
echo "Успешно выделили память\n";
} catch (\Throwable $e) {
echo "Ошибка: " . $e->getMessage() . "\n";
}
// Альтернативный способ: измерение предела
$limit = ini_get('memory_limit');
$limit_bytes = return_bytes($limit);
echo "Лимит в байтах: $limit_bytes\n";
function return_bytes($val) {
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
$val = (int) $val;
switch($last) {
case 'g': $val *= 1024;
case 'm': $val *= 1024;
case 'k': $val *= 1024;
}
return $val;
}
?>
Ошибка: Allowed memory size of 268435456 bytes exhausted (tried to allocate 2097152000 bytes) Лимит в байтах: 268435456
Пример 3: Запуск скрипта из командной строки с несколькими параметрами
Использование опции -d для временного переопределения memory_limit и других директив. Результат показывает значения, полученные внутри скрипта.
<?
// Пример 3: запуск из командной строки с несколькими директивами
// php -d memory_limit=512M -d max_execution_time=60 long_script.php
// Внутри скрипта:
echo "Режим: " . php_sapi_name() . "\n";
echo "memory_limit: " . ini_get('memory_limit') . "\n";
echo "max_execution_time: " . ini_get('max_execution_time') . "\n";
?>
Режим: cli memory_limit: 512M max_execution_time: 60
Пример 4: Сравнение значений php.ini и текущих настроек
Функция get_cfg_var возвращает значение из оригинального файла php.ini, игнорируя последующие изменения через ini_set или -d. Это помогает понять, какое значение было базовым.
<?
// Пример 4: определение приоритета настроек
// Если memory_limit установлен и через php.ini, и через ini_set, и через -d
// Проверим результат:
echo "memory_limit из php.ini (через ini_get): " . ini_get('memory_limit') . "\n";
// Сравнение с get_cfg_var (показывает значение из php.ini, игнорируя изменения)
echo "memory_limit из php.ini (через get_cfg_var): " . get_cfg_var('memory_limit') . "\n";
?>
memory_limit из php.ini (через ini_get): 512M memory_limit из php.ini (через get_cfg_var): 128M
Пример 5: Измерение потребления памяти при обработке файла
Отслеживание используемой памяти до и после загрузки большого файла в массив. Позволяет оценить, насколько скрипт требователен к памяти, и принять решение о лимите.
<?
// Пример 5: мониторинг пикового потребления при обработке большого файла
file_put_contents('test.txt', str_repeat('line', 100000));
$start_memory = memory_get_usage();
$file = file('test.txt');
$end_memory = memory_get_usage();
echo "Память до чтения: " . ($start_memory/1024/1024) . " МБ\n";
echo "Память после: " . ($end_memory/1024/1024) . " МБ\n";
echo "Пик: " . (memory_get_peak_usage()/1024/1024) . " МБ\n";
unlink('test.txt');
?>
Память до чтения: 0.42 МБ Память после: 3.81 МБ Пик: 4.01 МБ