Ошибка could not resize shared memory segment у PostgreSQL на Linux выглядит тревожно, но в большинстве случаев причина вполне приземлённая: процессу не хватает общей памяти, обычно в /dev/shm или в связанном с ним механизме tmpfs. Особенно часто это проявляется в Docker-контейнерах, где shared memory по умолчанию заметно меньше, чем ожидает база под реальной нагрузкой.
Типичный сценарий такой: PostgreSQL нормально стартует, проходит инициализацию, а затем под нагрузкой, во время тяжёлого запроса, сортировки, параллельного выполнения или обслуживания нескольких активных сессий подряд начинает падать с сообщением о невозможности увеличить сегмент shared memory. Иногда это всплывает сразу после увеличения shared_buffers, work_mem или после переезда базы в контейнер.
Сложность в том, что одно и то же сообщение может указывать на разные источники проблемы: маленький /dev/shm внутри контейнера, отдельный mount tmpfs от systemd, жёсткие memory-лимиты cgroup, нехватку RAM с учётом кэша и IPC или неудачное сочетание параметров PostgreSQL с параллелизмом.
Поэтому правильный порядок здесь важнее самого набора команд: сначала локализуем лимит, потом проверяем Docker и systemd, и только после этого трогаем параметры PostgreSQL. Частая ошибка — сразу уменьшать shared_buffers, хотя реальная проблема может быть вовсе не в нём.
Практическое правило простое: если PostgreSQL работает в контейнере и в ошибке есть намёк на /dev/shm, первым подозреваемым должен быть размер shared memory в Docker. Если база запущена как systemd-сервис с изоляцией, проверяем namespace, tmpfs и memory-ограничения. Если это обычная система без контейнера, смотрим фактический mount /dev/shm, доступную память и реальные параметры экземпляра.
Что означает ошибка PostgreSQL shared memory
Сообщение PostgreSQL could not resize shared memory segment означает, что сервер попытался увеличить сегмент общей памяти, но ОС отказала. В тексте ошибки часто виден путь вида /PostgreSQL.123456789 и системное пояснение вроде No space left on device или Cannot allocate memory. На Linux это нередко связано с POSIX shared memory, использующей /dev/shm.
Важно: это не всегда означает, что на сервере закончилась вся оперативная память. Очень часто проблема уже и локальнее — например, конкретный tmpfs ограничен 64 МБ, хотя на хосте свободны гигабайты. Именно поэтому в Docker ошибка может появляться даже на мощной машине.
Отдельный нюанс в том, что PostgreSQL использует shared memory не только для буферного кэша. На картину влияют параллельные запросы, динамическая shared memory, служебные операции, фоновые процессы и расширения. Из-за этого на тестах всё может быть спокойно, а в продакшене проблема проявится резко и неочевидно.
Если в логах фигурирует
/dev/shm, почти никогда не стоит начинать с тюнинга SQL. Сначала проверяют инфраструктурный лимит памяти, потом уже конфигурацию PostgreSQL.
Где проблема возникает чаще всего
Docker и Compose
У контейнеров Docker /dev/shm по умолчанию маленький. Для PostgreSQL, особенно при параллельных планах, построении индексов и тяжёлых сортировках, этого запаса часто недостаточно. База может стартовать без проблем, но падать на CREATE INDEX, больших ORDER BY, hash-операциях, аналитических запросах и массовом импорте.
systemd с изоляцией сервиса
Если PostgreSQL запускается не штатным юнитом пакета, а собственным systemd-сервисом с дополнительными параметрами безопасности, могли появиться настройки, меняющие видимость или размер временных файловых систем. Например, отдельные namespace, приватный /tmp, собственные tmpfs-монтирования или ограничение памяти.
Ограничения памяти через cgroup
Даже если /dev/shm формально выглядит достаточно большим, контейнер или сервис может быть ограничен по памяти. Тогда PostgreSQL пытается расширить shared memory, но фактически упирается в cgroup-лимит. Это особенно заметно в Docker с ограничением RAM или в systemd при использовании MemoryMax.
Неудачные настройки PostgreSQL
Слишком агрессивные значения shared_buffers, завышенный work_mem, большое число соединений и активный параллелизм сами по себе не всегда вызывают ошибку, но создают условия, при которых маленький /dev/shm становится критичным.
Если вам нужна более предсказуемая среда для базы и системных сервисов, такую нагрузку обычно удобнее размещать на отдельном VDS, где проще контролировать cgroup-лимиты, mount-параметры и ресурсы контейнеров.

Быстрая диагностика: что проверить первым делом
Начните с логов PostgreSQL. Нас интересует полный текст ошибки, особенно системное пояснение от ОС: No space left on device, Cannot allocate memory и похожие сообщения. По ним проще отличить нехватку места в tmpfs от общего memory pressure.
journalctl -u postgresql -n 100 --no-pager
journalctl -u docker -n 100 --no-pager
docker logs postgres
Дальше проверьте размер и заполнение /dev/shm именно там, где реально запущен PostgreSQL. Не на хосте вообще, а внутри контейнера или в контексте systemd-сервиса.
df -h /dev/shm
mount | grep shm
free -h
Если PostgreSQL работает в контейнере, смотрите внутрь него:
docker exec -it postgres df -h /dev/shm
docker exec -it postgres mount | grep shm
docker inspect postgres --format '{{.HostConfig.ShmSize}}'
Если последняя команда показывает 67108864, это и есть 64 МБ по умолчанию — для PostgreSQL этого часто мало.
После этого проверьте реальные параметры самой базы:
psql -U postgres -c "show shared_buffers;"
psql -U postgres -c "show work_mem;"
psql -U postgres -c "show max_connections;"
psql -U postgres -c "show max_parallel_workers;"
psql -U postgres -c "show dynamic_shared_memory_type;"
Если база работает под systemd, посмотрите, нет ли drop-in-конфигов и нестандартных ограничений:
systemctl cat postgresql
systemctl show postgresql -p MemoryMax -p PrivateTmp -p TemporaryFileSystem -p ProtectSystem
На практике этого уже хватает, чтобы локализовать значительную часть инцидентов. Если у вас контейнерная среда с усиленной изоляцией, полезно также понимать, как разные механизмы изоляции влияют на ресурсы процессов: об этом мы уже писали в материале про изоляцию контейнеров и её практические последствия.
Как исправить проблему в Docker
Если PostgreSQL работает в Docker, самое частое и правильное решение — явно увеличить shared memory для контейнера. То есть не «лечить» базу случайным уменьшением параметров, а дать ей нормальный размер /dev/shm.
Для разового запуска используйте параметр --shm-size:
docker run -d --name postgres --shm-size=1g -e POSTGRES_PASSWORD=secret postgres:16
Для Docker Compose задайте параметр в описании сервиса:
services:
postgres:
image: postgres:16
shm_size: 1gb
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Сколько ставить? Для маленьких установок часто хватает 256m или 512m, но если есть аналитические запросы, тяжёлые индексы, параллельные планы или просто активная база, разумнее начинать с 1g и смотреть по фактической нагрузке. Shared memory лучше выделять с запасом, а не впритык.
После изменения параметра контейнер нужно пересоздать. Обычный рестарт не всегда применяет новое значение, если контейнер уже был создан со старой конфигурацией.
docker compose down
docker compose up -d
Если одновременно заданы ограничения памяти контейнера, проверяйте их вместе с shm_size. Бессмысленно выдавать контейнеру /dev/shm на 1 ГБ, если весь контейнер ограничен, например, 512 МБ RAM.
Ещё один частый сценарий: база в контейнере, а мониторинг показывает свободную память на хосте. Это не опровергает проблему, потому что контейнерный /dev/shm — отдельный лимит, и он может закончиться независимо от общей памяти сервера.
Что делать, если PostgreSQL запущен как systemd-сервис
На обычной Linux-системе /dev/shm чаще всего смонтирован как tmpfs размером в долю от RAM. Но в systemd-сервисах ситуацию могут менять ограничения и переопределения. Если вы используете кастомный юнит, обязательно проверьте, не подменяете ли временные файловые системы и не урезаете ли ресурсы сервиса.
Сначала посмотрите текущий mount и размер:
df -h /dev/shm
mount | grep '/dev/shm'
Если размер слишком мал, проверьте, как смонтирован /dev/shm в системе. Временное решение можно применить через remount, но делать это стоит осознанно и в окно обслуживания:
mount -o remount,size=1G /dev/shm
Чтобы изменение переживало перезагрузку, обычно правят запись в /etc/fstab:
tmpfs /dev/shm tmpfs defaults,size=1G 0 0
Если дело именно в systemd-юните, проверьте, не задан ли для сервиса собственный TemporaryFileSystem или жёсткий лимит памяти. Часто проблема появляется после «усиления безопасности» по чужому шаблону, где в сервис без разбора добавили ограничивающие директивы.
systemctl cat postgresql
systemctl show postgresql -p MemoryMax -p TasksMax -p PrivateTmp -p TemporaryFileSystem
Если нашли ограничение через MemoryMax, оцените, достаточно ли его для PostgreSQL с текущими параметрами. Слишком низкий лимит способен ломать работу даже при нормальном размере /dev/shm.
Переопределение через drop-in может выглядеть так:
systemctl edit postgresql
[Service]
MemoryMax=0
После изменения перечитайте конфигурацию и перезапустите сервис:
systemctl daemon-reload
systemctl restart postgresql
Значение 0 здесь означает отсутствие лимита со стороны этой директивы. Но применять его стоит только если вы понимаете общую модель потребления памяти на сервере. Часто лучше задать реалистичный предел, а не снимать ограничение полностью.

Когда проблема не в /dev/shm, а в настройках PostgreSQL
Бывает и обратная ситуация: вы увеличили shm_size в Docker или размер системного /dev/shm, а ошибка или нестабильность остались. Тогда уже имеет смысл внимательно смотреть на конфигурацию самой базы.
Первый кандидат — shared_buffers. На небольших серверах его нередко выставляют слишком щедро, ориентируясь на усреднённые советы, но забывают про память ОС, файловый кэш, фоновые процессы, соединения и соседние сервисы. Если в контейнере у вас 2 ГБ RAM, а shared_buffers выставлен 1 ГБ, пространства для манёвра остаётся мало.
Второй кандидат — work_mem. Он не резервируется заранее на каждую сессию, но при активной параллельной нагрузке может резко увеличить фактическое потребление памяти. Поэтому большие значения «на всякий случай» — плохая практика. Лучше повышать его точечно для конкретных задач.
Третий фактор — параллелизм. Параметры max_parallel_workers, max_parallel_workers_per_gather и связанная с ними активность могут заметно увеличивать использование dynamic shared memory. Если сбой проявляется только на тяжёлых аналитических запросах, это очень вероятный след.
Как диагностический шаг можно временно уменьшить параллелизм и проверить, исчезает ли ошибка:
psql -U postgres -c "alter system set max_parallel_workers_per_gather = 0;"
psql -U postgres -c "select pg_reload_conf();"
Это не обязательно финальное решение, но полезная проверка. Если после отключения параллельных планов проблема пропала, значит shared memory действительно упиралась в динамические механизмы выполнения запросов.
Практический порядок исправления без лишнего риска
Чтобы не вносить сразу несколько изменений и не гадать, что именно помогло, лучше идти последовательно:
Соберите точный текст ошибки из логов PostgreSQL и ОС.
Проверьте размер
/dev/shmв том окружении, где реально работает процесс базы.Если это Docker — увеличьте
shm_sizeи пересоздайте контейнер.Если это systemd — проверьте
MemoryMax,TemporaryFileSystemи фактический mount/dev/shm.Оцените соотношение RAM сервера, лимитов cgroup и параметров PostgreSQL.
Только после этого корректируйте
shared_buffers,work_memи параллелизм.
Такой порядок почти всегда экономит время и уменьшает риск «починить» симптом, но оставить настоящую причину. Если вы часто гоняете обновления конфигов, миграции и проверку восстановления, полезно иметь отдельный контур для экспериментов — например, через подход с песочницей для тестов бэкапов и изменений.
Какие значения считать разумными
Универсальной цифры для /dev/shm нет, но есть практичные ориентиры. Для тестового контейнера PostgreSQL без тяжёлых запросов безопасный минимум — 256m. Для небольшой production-нагрузки чаще разумно сразу ставить 512m или 1g. Для аналитики, ETL, построения индексов и многопоточной обработки этого уже может быть мало.
С параметром shared_buffers тоже не стоит гнаться за максимумом. На небольших серверах лучше консервативная и предсказуемая конфигурация, чем агрессивный тюнинг по чужому шаблону. PostgreSQL хорошо использует и файловый кэш ОС, поэтому слишком большой shared_buffers не всегда даёт выигрыш.
Если база живёт в Docker, думайте о памяти в трёх слоях: RAM хоста, лимит контейнера и размер
/dev/shm. Узкое место может быть в любом из них.
Как убедиться, что проблема устранена
После изменения конфигурации не стоит ограничиваться фактом, что ошибка исчезла. Важно убедиться, что появился запас, а не просто немного отодвинулся порог сбоя.
Проверьте размер и заполнение
/dev/shmпосле рестарта.Убедитесь, что у контейнера или systemd-сервиса нет неожиданного memory-лимита.
Посмотрите логи PostgreSQL под типовой и пиковой нагрузкой.
Прогоните тяжёлые запросы, индексацию и batch-задачи.
Убедитесь, что после увеличения лимитов не начались OOM-события по другой причине.
Если есть тестовый стенд, воспроизведите сценарий с тем же профилем запросов. Если отдельного стенда нет, хотя бы прогоните типовые операции: создание индекса, массовый импорт, большой ORDER BY, hash join и параллельные выборки. Именно на них дефицит shared memory проявляется чаще всего.
Частые ошибки администраторов
Первая ошибка — смотреть df -h /dev/shm на хосте и считать, что этого достаточно. Для контейнеров такая проверка почти бесполезна, если вы не посмотрели то же самое внутри контейнера.
Вторая — увеличивать только shared_buffers после миграции на более мощный сервер и забывать, что в Docker остался дефолтный shm_size. В итоге конфигурация PostgreSQL стала тяжелее, а инфраструктурный лимит — нет.
Третья — бездумно задавать огромный work_mem. На одиночных запросах всё выглядит красиво, а под многопользовательской нагрузкой память начинает расходоваться лавинообразно.
Четвёртая — копировать жёстко ограничивающие настройки systemd из гайдов по hardening без понимания, как они влияют на базы данных. PostgreSQL не любит, когда ему внезапно меняют модель доступа к временным и shared-ресурсам.
Итог
Ошибка could not resize shared memory segment почти всегда указывает не на «сломанный PostgreSQL», а на нехватку shared memory в конкретной среде выполнения. На Linux это чаще всего /dev/shm, в Docker — слишком маленький shm_size, а в systemd — неудачные tmpfs или memory-ограничения.
Надёжный путь решения такой: сначала проверить, какой именно /dev/shm видит процесс, затем исключить лимиты Docker и systemd, после этого сверить конфигурацию PostgreSQL с реальным объёмом памяти. В большинстве случаев проблема устраняется быстро, если не перепрыгивать этапы диагностики.
Если кратко: увидели could not resize shared memory segment — сначала идите проверять /dev/shm, а не гадать на параметрах SQL. В таких инцидентах инфраструктура обычно объясняет поведение базы лучше любой теории.


