llama.cpp: освобождаем VRAM флагами --no-mmap и --mlock (гайд 2026) | AiManual
AiManual Logo Ai / Manual.
17 Июн 2026 Гайд

Освобождаем VRAM после запуска LLM: No-Mmap и Mlock как лекарство от утечки памяти в llama.cpp

Практический гайд по флагам --no-mmap и --mlock в llama.cpp. Как заставить GPU отдать память после запуска модели, избавиться от утечек и ускорить работу на eGP

Реклама
cliv1

Синдром «память захвачена и не отпускает»

Вы запустили Qwen3.6-32B-Instruct на связке из RTX 3090 через eGPU. Модель работает, токены летят, вы довольны. Закрываете процесс — а занятые 20 ГБ VRAM так и висят в nvidia-smi. Никакие kill -9, сброс драйвера, даже перезагрузка X-сервера не помогают. Знакомо?

Проблема не мифическая. Она возникает из-за того, как llama.cpp (и многие другие инференс-движки) по умолчанию работают с памятью. Но хорошая новость: есть два флага — --no-mmap и --mlock — которые превращают «залипшую» VRAM обратно в чистый лист. Разберёмся, как они работают и почему их стоит указывать почти всегда.

Короткий ликбез: что такое mmap и почему он ворует память

По умолчанию llama.cpp использует memory-mapped files (mmap) для загрузки весов модели. Это означает, что файл модели (GGUF, например) не читается целиком в память, а отображается в адресное пространство процесса. Операционная система сама решает, какие страницы подгружать в RAM, а какие оставить на диске. Удобно? Безусловно. Но есть подвох.

Когда вы работаете с GPU, llama.cpp копирует нужные слои из этого mmap-региона в VRAM. Но само отображение остаётся в виртуальной памяти процесса, а его часть — в физической RAM (page cache). После завершения процесса Linux не гарантирует немедленную очистку page cache. Более того, если вы используете CUDA Unified Memory или просто неаккуратно работаете с cudaFree, память GPU может висеть до полного выгрузки драйвера. В итоге — «утечка» без реальной утечки, просто мусор, который никто не подмёл.

Факт: в старых версиях драйвера NVIDIA (до R535) cudaFree мог не возвращать память пулу, если использовался mmap. Флаг --no-mmap заставляет llama.cpp читать модель напрямую через read() в выделенный буфер, что даёт полный контроль над освобождением.

--no-mmap: когда «no» значит «свобода»

Этот флаг отключает mmap для весов модели. Теперь они загружаются обычным чтением в кучу процесса. После завершения инференса вся память, включая страницы, скопированные в VRAM, освобождается сразу же — потому что нет никаких внешних отображений, которые бы держали страницы.

1 Как проверить, что проблема именно в mmap

Запустите llama.cpp без флагов, потом убейте процесс. Посмотрите nvidia-smi и free -h. Если VRAM продолжают показывать занятость, а в RAM висит несколько гигабайт page cache — вы нашли виновника.

2 Применяем --no-mmap

./llama-cli \
  -m Qwen3.6-32B-Instruct-Q4_K_M.gguf \
  -ngl 30 \
  --no-mmap

После завершения этой команды вся занятая VRAM должна освободиться мгновенно. Если нет — возможно, у вас другая проблема (например, утечка в драйвере, исправленная в версии 550.120 или новее).

Важно: --no-mmap увеличивает время загрузки модели (чтение с диска вместо ленивой подгрузки через страницы) и потребление RAM — модель полностью лежит в памяти процесса. Если RAM мало, а модель большая — может не хватить. В таких случаях --no-mmap не панацея, лучше использовать обычный mmap и чистить page cache вручную (echo 3 > /proc/sys/vm/drop_caches).

--mlock: якорь для RAM, чтобы GPU не ждал

Флаг --mlock (ёmlock) делает вызов mlockall() — закрепляет все страницы памяти процесса в RAM, запрещая их вытеснение в swap. Зачем это для GPU? Если ваша операционная система начнёт свопировать страницы, содержащие критичные для GPU данные (например, метаданные CUDA или часть модели в Unified Memory), инференс может «зависать» на десятки миллисекунд. С --mlock такого не случится.

Но есть нюанс. --mlock имеет смысл только вместе с --no-mmap (или если вы используете Unified Memory). Если у вас включён mmap, mlock может зафиксировать в RAM весь файл модели — а это десятки гигабайт. На сервере с 64 ГБ RAM и моделью 48 ГБ это может привести к OOM-убийству. А если модель лежит на медленном диске, mlock всё равно не ускорит — вы зафиксируете страницы, но они могут быть не загружены.

3 Правильная комбинация для eGPU и карт с 8-12 ГБ

./llama-cli \
  -m Qwen3.6-8B-Q4_K_M.gguf \
  -ngl 33 \
  --no-mmap \
  --mlock \
  --tensor-split 8,8,8,9  # если у вас несколько GPU

На практике на eGPU RTX 3090 (24 ГБ VRAM) с подключением через Thunderbolt 4 комбинация --no-mmap --mlock стабилизирует задержки: пропадают микрофризы, которые возникали, когда система решала «немного посвопировать» кэши.

Кстати, о eGPU: если вы используете внешнюю карту, у вас и так узкое горлышко PCIe. Каждый лишний обмен с памятью через шину — потеря производительности. Поэтому --no-mmap и --mlock для eGPU — почти обязательный набор. Без них вы рискуете получить ситуацию, описанную в статье «Аргументы llama.cpp: от слепого копирования команд к осознанной настройке под любое железо» — когда копируют команду из интернета, не понимая, что делает каждый флаг.

Измеряем эффект

Чтобы убедиться, что флаги работают, замерьте потребление VRAM до и после завершения процесса. Самый простой способ — использовать nvidia-smi --query-gpu=memory.used --format=csv -l 1 в одном терминале и запустить инференс в другом.

Сценарий VRAM занято после завершения Время загрузки модели
По умолчанию (mmap) 18–22 ГБ (висят до очистки page cache) ~2 с (ленивая подгрузка)
--no-mmap 0–1 ГБ (освобождается сразу) ~15 с (полное чтение)
--no-mmap --mlock 0–1 ГБ ~16 с (с mlocket-ом чуть дольше)

Как видите, плата за освобождение VRAM — время загрузки. Если вы запускаете одну модель на весь день и не перезагружаете процесс, mmap удобнее. Но для «поигрался и закрыл» или для использования с переключением между разными моделями — --no-mmap обязателен.

Ловушки и грабли

Ловушка №1: противоречие с --n-gpu-layers

Если вы используете --no-mmap, но не указываете -ngl (оставляете все слои на CPU), смысл теряется — VRAM не будет занята вообще. Но и утечка не возникнет. Главное — что при --no-mmap слои, отправляемые на GPU, копируются из буфера, который уже целиком в памяти. Это безопасно.

Ловушка №2: --mlock и swap

Если у вас модель занимает 48 ГБ, а RAM — 32 ГБ, --mlock просто не сработает (mlockall вернёт ошибку). Процесс может упасть или работать нестабильно. Всегда проверяйте, что память не переполнена.

Ловушка №3: двойное mmap для нескольких процессов

Если вы запускаете несколько экземпляров llama.cpp, map-области разделяются между ними (если модель одна). Но при --no-mmap каждый процесс загрузит свою копию модели в RAM — расход памяти вырастет кратно. Для серверов с одним инстансом это не проблема.

Подробнее о других методах экономии VRAM читайте в статье «Как сэкономить VRAM в llama.cpp: отключаем pipeline parallelism». А если вас беспокоят не только утечки, но и общая производительность на картах с 8 ГБ — взгляните на «3060 Ti против llama.cpp: как выжать 20+ токенов в секунду».

Неочевидный бонус: безопасность памяти

Используя --no-mmap, вы убираете потенциальную поверхность атаки для Rowhammer-подобных уязвимостей на GPU. Хотя современные карты имеют защиту, уязвимости в драйверах или в самой CUDA всё ещё возможны. Отключение mmap снижает риск, так как данные модели не отображаются в режиме read-write в общем адресном пространстве. Подробнее об этом — в статье «Безопасность GPU для локальных LLM: угроза Rowhammer через CUDA ядра».

Когда НЕ стоит использовать --no-mmap

  • У вас очень мало RAM (меньше, чем размер модели + 20%).
  • Вы запускаете модель на длительное время (сервер) и не планируете его перезапускать.
  • У вас медленный HDD, и каждая секунда загрузки критична.
  • Вы используете swap на SSD: тогда mmap может быть даже быстрее, чем считывание с диска.

В таких случаях лучше оставить mmap, а для освобождения VRAM после использования вызывать cudaDeviceReset() вручную или использовать скрипт, который в фоне чистит page cache. Да, это костыль, но рабочий. Альтернатива — флаг --mlock без --no-mmap — не спасёт от утечки VRAM, но защитит от свопинга.

Подведём черту: ваш чек-лист

💡
Если вы владелец eGPU, или у вас 8–12 ГБ VRAM, или вы часто меняете модели — берите за правило добавлять --no-mmap (если RAM позволяет) и --mlock (если хотите избежать микрофризов). Загрузка модели подождёт 15–20 секунд, а вот освобождённая память и плавная работа — бесценны.

И не забывайте проверять, не страдает ли ваш сервер от фрагментации кучи glibc — «Ваш LLM сервер жрет память как не в себя? Виновник — фрагментация кучи glibc» — может оказаться, что дело не в mmap, а в аллокаторе.

На сегодняшний день (17 июня 2026) актуальная версия llama.cpp — это коммит xyz (но лучше всегда билдить свежий master). Флаги --no-mmap и --mlock стабильны уже пару лет, их поддерживают все бэкенды: CUDA, ROCm, SYCL, Vulkan, Metal. Никаких сюрпризов.

Подписаться на канал