Настройка лимитов памяти PHP и MySQL на сайте в 2026 году

Правильная настройка лимитов памяти PHP и MySQL — это основа стабильной работы сайта. За 10+ лет практики я видел сотни проектов, которые тормозили или падали именно из-за неграмотно выставленных параметров памяти.

Зачем нужна настройка лимитов памяти

Честно говоря, многие разработчики недооценивают важность правильной настройки лимитов памяти. А зря. Неправильные параметры приводят к целому букету проблем. На практике я сталкивался с ситуациями, когда сайт работал нормально при небольшой нагрузке, но как только трафик увеличивался, начинались проблемы. Пользователи видели белые страницы, ошибки 500, а в логах появлялись записи о нехватке памяти. У одного клиента был интернет-магазин на WordPress с WooCommerce. Сайт работал стабильно, пока не запустили рекламную кампанию. Количество одновременных посетителей выросло в 3 раза, и сайт начал падать. Проблема была в том, что memory_limit стоял на стандартных 128M, а каждая страница товара потребляла около 80-90M памяти из-за тяжёлых плагинов. И это только PHP. С MySQL ситуация ещё интереснее. Неправильно настроенные буферы могут как ускорить работу в разы, так и полностью положить сервер. Видел случаи, когда innodb_buffer_pool_size выставляли слишком большим на слабом VPS, и система начинала использовать swap, что замедляло все запросы в десятки раз.
⚠️
Важно понимать: лимиты памяти — это не просто числа в конфигах. Это баланс между производительностью и стабильностью системы. Слишком маленькие значения приведут к ошибкам, слишком большие — к нехватке ресурсов для других процессов.
Основные проблемы при неправильной настройке: - Ошибки "Fatal error: Allowed memory size exhausted" в PHP - Медленные запросы в MySQL из-за недостатка буферов - Использование swap-файла вместо оперативной памяти - Нестабильная работа при пиковых нагрузках - Падение производительности сайта

Основы управления памятью в PHP

PHP управляет памятью довольно специфично. В отличие от языков с ручным управлением памятью, PHP автоматически выделяет и освобождает память, но в рамках установленных лимитов. Основной параметр — это memory_limit. Он определяет максимальное количество памяти, которое может использовать один PHP-процесс. По умолчанию в PHP 8.1-8.3 это значение составляет 128M, но для современных CMS этого катастрофически мало. На моей практике оптимальные значения для разных типов проектов: - Простые сайты на чистом PHP: 256M - WordPress с базовыми плагинами: 512M - Битрикс: 1024M (иногда больше) - Laravel с активным использованием Eloquent: 512-1024M - Интернет-магазины: 1024-2048M Но memory_limit — не единственный параметр. Есть ещё max_execution_time, который ограничивает время выполнения скрипта. По умолчанию это 30 секунд, но для некоторых операций (импорт товаров, обработка изображений) может потребоваться больше времени. Ещё один важный параметр — post_max_size и upload_max_filesize. Они влияют на размер данных, которые можно отправить на сервер. Если у вас есть формы загрузки файлов, эти параметры должны быть настроены правильно.

; Пример оптимальной настройки для WordPress
memory_limit = 512M
max_execution_time = 300
max_input_time = 300
post_max_size = 64M
upload_max_filesize = 64M
max_file_uploads = 20

; Для Битрикс обычно нужно больше
memory_limit = 1024M
max_execution_time = 600
post_max_size = 128M
upload_max_filesize = 128M
А вот с какими проблемами я сталкивался на практике. У одного клиента был сайт на Laravel, где пользователи могли загружать большие Excel-файлы для импорта данных. memory_limit стоял на 256M, но обработка файла на 50MB потребляла около 800M памяти. Решение было простое — увеличить лимит до 1024M и оптимизировать код для чтения файла по частям.

Настройка PHP memory_limit на разных системах

Способ настройки memory_limit зависит от того, как у вас настроен PHP. Есть несколько основных сценариев. Если PHP работает как модуль Apache (mod_php), то настройки можно менять в php.ini, .htaccess или прямо в коде. Самый надёжный способ — через php.ini:

; В файле php.ini
memory_limit = 1024M

; Не забываем перезапустить Apache после изменений
sudo systemctl restart apache2
Для настройки через .htaccess (если позволяет хостинг):

# В файле .htaccess
php_value memory_limit 1024M
php_value max_execution_time 300
php_value post_max_size 128M
php_value upload_max_filesize 128M
При использовании PHP-FPM (что сейчас более распространено), настройки нужно менять в конфигурационном файле пула. Обычно это файл вида /etc/php/8.1/fpm/pool.d/www.conf:

; В конфигурации PHP-FPM пула
php_admin_value[memory_limit] = 1024M
php_admin_value[max_execution_time] = 300
php_admin_value[post_max_size] = 128M
php_admin_value[upload_max_filesize] = 128M

; После изменений перезапускаем PHP-FPM
sudo systemctl restart php8.1-fpm
Если вы работаете с Docker, то настройки можно передать через переменные окружения или кастомный php.ini:

FROM php:8.1-fpm

# Создаём кастомный php.ini
COPY custom-php.ini /usr/local/etc/php/conf.d/

# Или через переменные окружения
ENV PHP_MEMORY_LIMIT=1024M
ENV PHP_MAX_EXECUTION_TIME=300
Был случай у клиента с сайтом на shared-хостинге, где нельзя было менять php.ini. Хостер позволял настройки только через .htaccess, но даже там были ограничения. memory_limit можно было увеличить максимум до 512M. Пришлось оптимизировать код и ускорить WordPress за счёт кеширования и отключения лишних плагинов.
💡
Лайфхак: Чтобы узнать текущие настройки PHP, создайте файл info.php с содержимым и откройте его в браузере. Там будет вся информация о конфигурации.
На продакшене я всегда рекомендую настраивать лимиты через конфигурационные файлы, а не в коде. Это более надёжно и позволяет легко управлять настройками без изменения кода приложения.

Оптимизация использования памяти MySQL

MySQL использует память совсем по-другому, чем PHP. Здесь есть множество буферов и кешей, каждый из которых выполняет свою функцию. Неправильная настройка может как ускорить работу в разы, так и полностью положить сервер. Основной параметр — innodb_buffer_pool_size. Это кеш для хранения данных и индексов InnoDB в памяти. По умолчанию он составляет всего 128M, что абсолютно недостаточно для любого серьёзного проекта. На практике я использую следующие рекомендации: - Для VPS с 2GB RAM: 1GB для buffer pool (50%) - Для VPS с 4GB RAM: 2.5GB для buffer pool (60-65%) - Для выделенного сервера с 16GB: 10-12GB для buffer pool (70-75%) Важно не выделять всю память под MySQL. Системе нужна память для PHP, веб-сервера, операционной системы. Обычно под MySQL выделяю 60-75% от общей памяти сервера.

[mysqld]
# Основной буфер для InnoDB (самый важный параметр)
innodb_buffer_pool_size = 2G

# Размер лог-файлов InnoDB
innodb_log_file_size = 256M
innodb_log_buffer_size = 64M

# Буфер для сортировки и временных таблиц
sort_buffer_size = 2M
tmp_table_size = 256M
max_heap_table_size = 256M

# Кеш для MyISAM таблиц (если используются)
key_buffer_size = 128M

# Буфер для чтения
read_buffer_size = 1M
read_rnd_buffer_size = 2M

# Кеш запросов (в MySQL 8.0 удалён)
query_cache_size = 0
query_cache_type = 0
У меня был интересный случай с клиентом, у которого сайт работал на VPS с 8GB памяти. Разработчики выставили innodb_buffer_pool_size в 6GB, думая, что больше — значит лучше. Но они забыли про PHP-FPM, Apache и систему. В результате сервер начал активно использовать swap, и производительность упала в разы. Пришлось уменьшить buffer pool до 4GB, и всё заработало отлично.
⚠️
Осторожно: Изменение innodb_log_file_size требует специальной процедуры. Нужно остановить MySQL, удалить старые лог-файлы и запустить заново. Всегда делайте бэкап перед такими изменениями!
Для мониторинга использования памяти MySQL использую такие запросы:

-- Проверяем статус InnoDB buffer pool
SHOW ENGINE INNODB STATUS\G

-- Смотрим использование памяти
SELECT 
  SUBSTRING_INDEX(SUBSTRING_INDEX(@@version, '-', 1), '.', 2) as mysql_version,
  @@innodb_buffer_pool_size / 1024 / 1024 / 1024 as buffer_pool_gb,
  @@innodb_log_file_size / 1024 / 1024 as log_file_mb;

-- Анализируем эффективность buffer pool
SELECT 
  VARIABLE_NAME, 
  VARIABLE_VALUE 
FROM performance_schema.global_status 
WHERE VARIABLE_NAME LIKE 'Innodb_buffer_pool%';
Отдельно стоит упомянуть про MySQL 8.0. Там появились новые возможности для управления памятью, но убрали query cache. Если вы мигрируете с MySQL 5.7, нужно пересмотреть конфигурацию. Подробнее об этом я писал в статье про оптимизацию базы данных MySQL.

Мониторинг памяти в реальном времени

Настроить лимиты — это только половина дела. Важно постоянно следить за тем, как система использует память. На продакшене я всегда настраиваю мониторинг, который позволяет быстро выявить проблемы. Для мониторинга PHP использую несколько подходов. Первый — логирование пикового использования памяти в каждом скрипте:

 100 * 1024 * 1024) { // Если больше 100MB
        error_log("High memory usage: Peak {$memory_peak}, Current {$memory_current}, Script: " . $_SERVER['REQUEST_URI']);
    }
});

// Для WordPress можно добавить в functions.php
add_action('wp_footer', function() {
    if (current_user_can('administrator') && isset($_GET['debug_memory'])) {
        echo "";
    }
});
Для системного мониторинга использую комбинацию инструментов. На большинстве проектов устанавливаю Zabbix или Prometheus с Grafana. Но для быстрой диагностики подходят и простые bash-скрипты:

#!/bin/bash
# Скрипт для мониторинга памяти (memory_monitor.sh)

while true; do
    echo "=== $(date) ==="
    
    # Общая информация о памяти
    free -h
    
    # Топ процессов по использованию памяти
    echo "Top memory consumers:"
    ps aux --sort=-%mem | head -10
    
    # Статистика PHP-FPM
    echo "PHP-FPM processes:"
    ps aux | grep php-fpm | grep -v grep | wc -l
    
    # Использование swap
    echo "Swap usage:"
    swapon -s
    
    echo "===================="
    sleep 60
done
У одного клиента возникла интересная ситуация. Сайт периодически становился недоступным, но в логах ошибок ничего не было. Оказалось, что PHP-FPM процессы накапливались и съедали всю память. Проблема была в том, что pm.max_requests стоял на 0 (без лимита), и процессы никогда не перезапускались. Утечки памяти в коде накапливались, и в итоге система падала.
💡
Полезно знать: В PHP-FPM можно настроить автоматический перезапуск процессов при превышении лимита памяти. Параметр pm.max_requests = 1000 заставит процесс перезапуститься после обработки 1000 запросов.
Для мониторинга MySQL использую встроенные инструменты:

-- Мониторинг использования памяти MySQL
SELECT 
  FORMAT_BYTES(@@innodb_buffer_pool_size) as buffer_pool_size,
  FORMAT_BYTES(@@key_buffer_size) as key_buffer_size,
  FORMAT_BYTES(@@sort_buffer_size) as sort_buffer_size,
  FORMAT_BYTES(@@tmp_table_size) as tmp_table_size;

-- Статистика buffer pool
SELECT 
  POOL_ID,
  POOL_SIZE,
  FREE_BUFFERS,
  DATABASE_PAGES,
  OLD_DATABASE_PAGES
FROM information_schema.INNODB_BUFFER_POOL_STATS;
На критически важных проектах настраиваю алерты. Если использование памяти превышает 80%, система отправляет уведомление. Это позволяет предотвратить проблемы до того, как они повлияют на пользователей.

Оптимизация кода для эффективного использования памяти

Даже с правильно настроенными лимитами памяти, плохо написанный код может свести на нет все усилия. За годы практики я выработал несколько принципов, которые помогают писать memory-friendly код. Первое правило — избегать загрузки больших объёмов данных в память. Особенно это касается работы с базой данных. Вместо SELECT * FROM table WHERE..., лучше использовать постраничную загрузку или курсоры:

get(); // Может быть 100k записей
foreach ($products as $product) {
    // Обработка
}

// Хорошо - обрабатываем по частям
DB::table('products')->chunk(1000, function($products) {
    foreach ($products as $product) {
        // Обработка 1000 записей за раз
    }
});

// Ещё лучше - используем курсор (Laravel 8+)
foreach (DB::table('products')->lazy() as $product) {
    // Обработка по одной записи
}
Второй принцип — правильная работа с циклами. В PHP особенно важно освобождать память в длинных циклах:

Третий принцип касается работы с изображениями. Обработка изображений — один из самых "прожорливых" по памяти процессов. Изображение размером 3000x2000 пикселей требует около 24MB памяти в несжатом виде:

 100 * 1024 * 1024) { // Больше 100MB
        throw new Exception("Image too large for processing");
    }
    
    $image = imagecreatefromjpeg($sourcePath);
    
    if ($width > $maxWidth) {
        $newHeight = ($height / $width) * $maxWidth;
        $resized = imagecreatetruecolor($maxWidth, $newHeight);
        imagecopyresampled($resized, $image, 0, 0, 0, 0, $maxWidth, $newHeight, $width, $height);
        
        imagejpeg($resized, $targetPath, 85);
        imagedestroy($resized);
    } else {
        imagejpeg($image, $targetPath, 85);
    }
    
    imagedestroy($image);
}
У меня был клиент с фотогалереей, где пользователи загружали фотографии с камер высокого разрешения. Изначально код загружал оригинал в память, создавал несколько размеров миниатюр, а потом сохранял. При обработке фото 6000x4000 пикселей скрипт потреблял больше 500MB памяти. Пришлось переписать логику: сначала создаём уменьшенную копию, а уже с неё делаем миниатюры. Четвёртый принцип — правильная работа с объектами. В PHP объекты могут создавать циклические ссылки, которые не освобождаются автоматически:

data = null;
    }
    
    public function processLargeDataset($dataset) {
        foreach ($dataset as $item) {
            $this->data[] = $this->processItem($item);
            
            // Периодически очищаем обработанные данные
            if (count($this->data) > 1000) {
                $this->flushData();
            }
        }
    }
    
    private function flushData() {
        // Сохраняем данные и очищаем массив
        $this->saveData($this->data);
        $this->data = [];
        
        // Принудительно запускаем сборщик мусора
        gc_collect_cycles();
    }
}
Эти принципы особенно важны при работе с большими проектами. Недавно помогал клиенту оптимизировать импорт товаров в интернет-магазине. Изначально скрипт загружал весь CSV в память (файл был на 500MB), а потом обрабатывал. После оптимизации стали читать файл построчно и обрабатывать по 100 товаров за раз. Потребление памяти снизилось с 2GB до 50MB.

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

За годы работы я столкнулся с множеством проблем, связанных с памятью. Некоторые из них встречаются настолько часто, что стоит разобрать их отдельно. **Проблема 1: "Fatal error: Allowed memory size exhausted"** Это самая частая ошибка. Обычно она означает, что скрипт пытается использовать больше памяти, чем позволяет memory_limit. Но не всегда решение заключается в простом увеличении лимита. Сначала я всегда анализирую, почему скрипт потребляет много памяти:

 1024; $i++) {
        $bytes /= 1024;
    }
    
    return round($bytes, $precision) . ' ' . $units[$i];
}

// Используем в коде
logMemoryUsage("Start");
$data = loadLargeDataset();
logMemoryUsage("After loading data");
processData($data);
logMemoryUsage("After processing");
**Проблема 2: Медленные запросы из-за нехватки памяти MySQL** Часто встречаю ситуацию, когда сложные запросы выполняются очень долго из-за недостатка памяти для сортировки или создания временных таблиц:

-- Проверяем статистику временных таблиц
SHOW GLOBAL STATUS LIKE 'Created_tmp%';

-- Если Created_tmp_disk_tables большое, нужно увеличить tmp_table_size
SET GLOBAL tmp_table_size = 512 * 1024 * 1024; -- 512MB
SET GLOBAL max_heap_table_size = 512 * 1024 * 1024; -- 512MB

-- Проверяем использование sort_buffer
SHOW GLOBAL STATUS LIKE 'Sort_merge_passes';
-- Если значение большое, увеличиваем sort_buffer_size
**Проблема 3: Утечки памяти в PHP-FPM** PHP-FPM процессы могут накапливать память из-за утечек в коде. Решение — настроить автоматический перезапуск процессов:

; В конфигурации PHP-FPM пула
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15

; Автоматический перезапуск при превышении лимитов
pm.max_requests = 1000
pm.process_idle_timeout = 60s

; Ограничение памяти на процесс
request_terminate_timeout = 300
**Проблема 4: Swap активно используется** Если система начинает активно использовать swap, производительность падает катастрофически. Проверяю это командой:

# Проверяем использование swap
free -h
swapon -s

# Смотрим, какие процессы используют swap
for file in /proc/*/smaps; do
    awk '/Swap:/ { swap += $2 } END { print FILENAME, swap }' $file
done | sort -k2 -n | tail -10

# Если swap используется активно, уменьшаем swappiness
echo 'vm.swappiness=10' >> /etc/sysctl.conf
sysctl -p
Был случай у клиента с сайтом на Битрикс. Сервер имел 8GB памяти, но система постоянно использовала swap. Оказалось, что innodb_buffer_pool_size был выставлен в 6GB, а PHP-FPM был настроен на 50 процессов по 256MB каждый. В пиковые моменты получалось: 6GB (MySQL) + 12.5GB (PHP) + система = больше 18GB. Пришлось уменьшить buffer pool до 4GB и ограничить количество PHP процессов до 20.
ℹ️
Профилактика: Регулярно мониторьте использование памяти и настройте алерты. Лучше получить уведомление о проблеме за 15 минут до её возникновения, чем разбираться с упавшим сайтом.
**Проблема 5: OOM Killer убивает процессы** В критических ситуациях Linux может принудительно завершить процессы, потребляющие много памяти. Это логируется в /var/log/kern.log:

# Проверяем логи OOM Killer
grep -i "killed process" /var/log/kern.log
dmesg | grep -i "killed process"

# Анализируем какие процессы чаще убиваются
grep -i "killed process" /var/log/kern.log | awk '{print $9}' | sort | uniq -c | sort -nr
Если OOM Killer регулярно убивает процессы, значит сервер перегружен и нужно либо добавить памяти, либо оптимизировать настройки.

Рекомендации для разных типов проектов в 2026 году

Настройки памяти сильно зависят от типа проекта и используемых технологий. Поделюсь своими наработками для разных сценариев. **Простые сайты-визитки на чистом PHP:** - memory_limit: 256M - innodb_buffer_pool_size: 256M (для VPS 2GB) - PHP-FPM: pm.max_children = 10 Такие сайты обычно потребляют мало ресурсов. Основная нагрузка — отдача статического контента и простые формы обратной связи. **WordPress с базовыми плагинами:** - memory_limit: 512M - innodb_buffer_pool_size: 1GB (для VPS 4GB) - PHP-FPM: pm.max_children = 20 - object cache (Redis): 256M WordPress сам по себе довольно "тяжёлый", а плагины могут значительно увеличить потребление памяти. Особенно прожорливые — плагины для SEO, конструкторы страниц, системы кеширования. **Битрикс (стандартная редакция):** - memory_limit: 1024M - innodb_buffer_pool_size: 2-4GB - PHP-FPM: pm.max_children = 25 - max_execution_time: 600 Битрикс известен высоким потреблением ресурсов. Особенно это заметно в административной части и при работе с большими каталогами товаров.

// Специфичные настройки для Битрикс в .htaccess
php_value memory_limit 1024M
php_value max_execution_time 600
php_value max_input_time 600
php_value post_max_size 128M
php_value upload_max_filesize 128M
php_value session.gc_maxlifetime 14400

# Включаем сжатие
php_flag zlib.output_compression on
php_value zlib.output_compression_level 6
**Интернет-магазины (WooCommerce, Bitrix Commerce):** - memory_limit: 1024-2048M - innodb_buffer_pool_size: 4-8GB - PHP-FPM: pm.max_children = 30-50 - Обязательно Redis/Memcached для кеширования Интернет-магазины — самые требовательные к ресурсам проекты. Большие каталоги, сложная логика расчёта цен, интеграции с платёжными системами и службами доставки. **Laravel-приложения:** - memory_limit: 512-1024M - innodb_buffer_pool_size: 2-4GB - PHP-FPM: pm.max_children = 20-30 - Queue worker: отдельные лимиты памяти

# Настройка queue worker в supervisor
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/app/artisan queue:work --sleep=3 --tries=3 --max-time=3600 --memory=512
autostart=true
autorestart=true
user=www-data
numprocs=8
redirect_stderr=true
stdout_logfile=/var/log/laravel-worker.log
**Высоконагруженные проекты:** Для проектов с высокой нагрузкой использую более агрессивные настройки и дополнительные инструменты:

; PHP-FPM для высокой нагрузки
pm = static
pm.max_children = 100
pm.max_requests = 10000
pm.process_idle_timeout = 10s

; MySQL для высокой нагрузки
innodb_buffer_pool_size = 12G
innodb_buffer_pool_instances = 8
innodb_log_buffer_size = 256M
innodb_log_file_size = 2G
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
У одного клиента есть новостной портал с посещаемостью 100k уникальных посетителей в день. Пиковая нагрузка приходится на утренние часы (7-10 утра), когда одновременно онлайн находится до 2000 пользователей. Для такого проекта мы используем: - 3 сервера приложений с 16GB RAM каждый - Отдельный сервер базы данных с 64GB RAM - Redis-кластер для кеширования - CDN для статического контента Настройки постоянно мониторим и корректируем на основе реальных данных. Например, заметили, что в пиковые часы MySQL начинает создавать много временных таблиц на диске. Увеличили tmp_table_size до 1GB, и проблема решилась.
💡
Важное замечание: Все эти настройки — это отправная точка. Реальные значения нужно подбирать на основе мониторинга конкретного проекта. То, что работает для одного сайта, может не подойти для другого.
Для тестирования настроек использую инструменты нагрузочного тестирования. Apache Bench (ab) для простых случаев, JMeter для сложных сценариев. Это помогает понять, как система ведёт себя под нагрузкой и где находятся узкие места. Если у вас возникли сложности с настройкой лимитов памяти или оптимизацией производительности, моя команда может помочь. Мы предоставляем услуги поддержки Битрикс и поддержки WordPress, включая настройку серверного окружения и оптимизацию производительности.

Нужна помощь с оптимизацией сервера?

Наши эксперты помогут настроить оптимальные параметры памяти для максимальной производительности вашего сайта.

П
Павел
Веб-разработчик · 10+ лет опыта · Bitrix, WordPress, Laravel

Читайте также

Laravel для бизнес-проекта: когда и зачем Переход на HTTPS: полный чек-лист Доработка сайта: что можно улучшить