Когда 4 ГБ ОЗУ - это не приговор, а вызов
В 2026 году запустить LLM на телефоне с 8 ГБ оперативки - это уже банальность. Настоящий кайф начинается, когда у тебя в руках устройство с 4 ГБ, которое постоянно напоминает: "Памяти не хватает, закрой что-нибудь". Именно на таком железе я решил запустить локальную языковую модель. Не для хайпа. Не для скриншотов в Twitter. А потому что реальные люди используют реальные телефоны, а не флагманы за тысячу долларов.
Если вы думаете, что 4 ГБ в 2026 - это смешно, посмотрите статистику: 43% Android-устройств в мире до сих пор работают с 4 ГБ ОЗУ или меньше. Это не нишевый кейс - это массовый рынок.
Почему стандартные подходы не работают
Первое, что делают новички - качают llama.cpp и пытаются запустить Qwen2.5-3B. Результат предсказуем: приложение крашится через 30 секунд. Система убивает процесс, потому что он съедает всю доступную память. В логах - классическое "Out of memory", но без деталей, что именно пошло не так.
Проблема в том, что мобильные ОС агрессивно управляют памятью. Android не просто выделяет RAM - он считает, сколько приложение может взять, прежде чем начать убивать другие процессы. Когда вы запускаете LLM, система видит: "О, этот процесс хочет 3.5 ГБ из 4!" И немедленно принимает меры.
Выбор модели: не все 3B-модели одинаковы
Здесь начинается самое интересное. Размер модели в параметрах - это одно. Реальный расход памяти - совсем другое. После тестирования десятков вариантов я выделил три категории:
| Модель | Формат | Память (пик) | Стабильность |
|---|---|---|---|
| Gemma 3B-1tLiterltm | GGUF Q4_K_S | 2.8-3.2 ГБ | Высокая |
| Qwen2.5-3B | GGUF Q4_0 | 3.5-4.1 ГБ | Низкая |
| Phi-3-mini | GGUF Q4_K_M | 2.5-2.9 ГБ | Средняя |
Gemma 3B-1tLiterltm в 500 МБ варианте - это не опечатка. Модель специально оптимизирована для мобильных устройств с урезанным словарем и архитектурными изменениями, которые снижают потребление памяти на 30-40% по сравнению с vanilla Gemma 3B.
Проблема с GGUF: почему форматы имеют значение
Большинство руководств рекомендуют Q4_K_M как оптимальный баланс качества и размера. На слабом Android это смертный приговор. Формат Q4_K_M требует дополнительных вычислений для деквантования, что увеличивает пиковое потребление памяти на 15-20%.
Вот что происходит на самом деле:
- Загружаем модель: 2.1 ГБ
- Выделяем буферы для контекста: +300 МБ
- Деквантуем первые слои: +400 МБ (временный пик)
- Система видит 2.8 ГБ и паникует
Решение? Использовать Q4_0 или Q4_K_S. Да, качество немного страдает. Но модель хотя бы запускается.
1 Подготовка системы: освобождаем каждый мегабайт
Перед запуском LLM нужно сделать то, что не делают 99% пользователей: почистить системный кэш. Не через настройки Android (это поверхностно), а через ADB:
adb shell pm trim-caches 999999999
adb shell "cmd activity force-stop com.android.systemui"
Первая команда принудительно очищает кэши всех приложений. Вторая - перезапускает SystemUI, который в современных Android версиях может занимать до 500 МБ RAM.
Внимание: перезапуск SystemUI на секунду-две "уронит" интерфейс. Не пугайтесь черного экрана - это нормально.
2 Настройка llama.cpp: флаги, которые спасают
Стандартная команда запуска не подходит. Нужны специфические флаги, которые ограничивают аппетиты модели:
./main -m gemma-3b-1tliterltm-q4_k_s.gguf \
-c 512 \
-b 128 \
--mlock \
--no-mmap \
--threads 4 \
--memory-f32 \
--temp 0.7
Разберем каждый флаг:
- -c 512: ограничение контекста. Не пытайтесь ставить 2048 - съедите всю память
- -b 128: размер батча. Меньше = меньше пиковая память
- --mlock: фиксирует модель в RAM, предотвращая свопинг (на Android свопинг убивает производительность)
- --no-mmap: загружает модель целиком в память. Кажется контрпродуктивным, но на Android mmap ведет себя непредсказуемо
- --threads 4: не используйте все ядра! Оставьте 2-3 ядра системе
- --memory-f32: использует float32 для вычислений в памяти. Медленнее, но стабильнее на слабом железе
3 Борьба с крашами: мониторинг и предупреждение
Краш неизбежен. Вопрос в том, как его предсказать и минимизировать ущерб. Я написал простой скрипт для Termux, который мониторит потребление памяти:
#!/data/data/com.termux/files/usr/bin/python3
import subprocess
import time
import sys
MEMORY_THRESHOLD = 3500 # 3.5 ГБ в МБ
while True:
try:
# Получаем использование памяти процессом
result = subprocess.run(
['ps', '-o', 'rss=', '-p', str(sys.argv[1])],
capture_output=True,
text=True
)
memory_mb = int(result.stdout.strip()) // 1024
if memory_mb > MEMORY_THRESHOLD:
print(f"\n⚠️ Критическое использование памяти: {memory_mb} МБ")
print("Сбрасываю контекст...")
# Отправляем сигнал сброса контекста
subprocess.run(['pkill', '-USR1', 'main'])
time.sleep(2)
time.sleep(5)
except KeyboardInterrupt:
break
except:
continue
Этот скрипт запускается параллельно с llama.cpp и отслеживает потребление памяти. При приближении к критической отметке он отправляет сигнал сброса контекста, что освобождает 200-300 МБ.
Ограничение токенов: жесткая экономия
На слабом Android нельзя позволить себе роскошь длинных диалогов. Каждый токен - это память. Моя стратегия:
- Максимальная длина ответа: 256 токенов
- Автоматическая очистка контекста после 3 обменов репликами
- Запрет на генерацию кода (слишком много токенов)
- Использование system prompt для ограничения verbosity модели
System prompt выглядит так:
Ты работаешь на устройстве с ограниченной памятью. Будь краток. Максимальная длина ответа - 3 предложения. Не генерируй код. Не перечисляй пункты списком.
Сравнение производительности в разных задачах
После недели тестов на Xiaomi Redmi Note 11 (4 ГБ ОЗУ, Snapdragon 680) получились такие цифры:
| Задача | Скорость (токен/сек) | Память (пик) | Стабильность |
|---|---|---|---|
| Ответ на вопрос | 4-6 | 3.1 ГБ | 95% |
| Перевод текста | 3-5 | 3.3 ГБ | 85% |
| Суммаризация | 2-4 | 3.4 ГБ | 75% |
4-6 токенов в секунду - это не скорость, а выживание. Но для ответов на вопросы в офлайн-режиме достаточно. Главное - не пытаться вести философские диалоги.
Альтернативы: когда llama.cpp не вариант
Если даже с оптимизациями модель не запускается, есть другие пути:
- MLC Chat с Vulkan-рендерингом. В нашей статье про запуск LLM на Android с NPU мы подробно разбирали этот подход. MLC компилирует модель под конкретное железо, что может снизить потребление памяти на 20-30%.
- Распределенные вычисления через AI-Doomsday-Toolbox. Если есть второй телефон, можно распределить слои модели между устройствами. Подробности в статье про AI-Doomsday-Toolbox.
- Серверный режим: запустить модель на домашнем сервере, а на телефоне использовать тонкий клиент. Не совсем локально, но работает даже на самых слабых устройствах.
Чего точно не стоит делать
Из горького опыта:
Не пытайтесь запускать модели больше 3B параметров. Даже в 2-битном квантовании. Система убьет процесс.
Не используйте флаг --flash-attn. На слабых процессорах он дает прирост 5%, но увеличивает потребление памяти на 15%.
Не запускайте LLM в фоне. Android агрессивно убивает фоновые процессы с высоким потреблением памяти.
Будущее мобильных LLM на слабом железе
К 2027 году ситуация изменится. Уже сейчас появляются модели с архитектурными оптимизациями специально для мобильных устройств. Gemma 3B-1tLiterltm - только начало. Ожидайте:
- Модели с динамическим квантованием (разные слои - разная точность)
- Архитектуры, которые умеют "разгружать" части себя на диск без потери производительности
- Специализированные ядра в процессорах для LLM-инференса (не только NPU)
Но пока что - это ручная работа. Настройка каждого флага. Мониторинг каждого мегабайта. Борьба с каждой ошибкой. Зато когда модель наконец отвечает на вопрос в офлайне, на слабом телефоне, который "не должен был это потянуть" - это чувство стоит всех потраченных часов.
Потому что это не про технологии. Это про то, чтобы ИИ стал доступным не только тем, у кого есть деньги на флагман. А всем.