На Mac mini / Cloud Mac при параллельном запуске Ollama, Claude Code и GitHub Actions чаще всего проблема не «мало производительности», а swap, рывки CLI и замедление CI.
В этой статье без установки инструментов: почему при трёх параллельных AI-workload память «дрожит» и как scheduling это предотвращает. Антипример, бюджет памяти, пороги, runbook на 30 с и полный скрипт — без повтора бенчмарка 16GB vs 24GB.
TL;DR
- Постоянный Ollama + burst CI → на M4 swap очень част (см. антипример)
- Решение обычно не в апгрейде Mac, а план слоёв для burst / interactive / background
- Перед CI
ollama stop— самый важный и простой шаг (версия на 30 с)
Модель AI workload scheduling: на Cloud Mac большинство swap/OOM — из-за scheduling, а не абсолютного дефицита RAM.
Настоящая проблема: чаще не нехватка RAM, а отсутствие приоритетов
Симптомы: «пустой локальный модель + пик CI + тормозит агент» — часто ошибочно «купить RAM».
В сценариях Cloud Mac большинство swap/OOM — из-за scheduling workload, а не абсолютного дефицита RAM. На одном Mac mini три типа нагрузки (см. ниже):
- Burst — GitHub Runner /
xcodebuild, при push +4–8 GB - Interactive — Claude Code, IDE + Terminal + großes Repo
- Background — lokale Inference wie Ollama; geladenes 8B hält still 5–7 GB
По умолчанию все равноправно делят unified memory — никто «не обязан уступать».Направление: задать приоритеты и триггеры, сделать background-inference снимаемым и вытесняемым CI.
Плохое планирование (на M4 часто, не редкость)
Комбинация, которую мы видели на Cloud Mac в малых командах — «запретный режим» при onboarding:
Bad pattern · all three workloads default「full on」 qwen3:8b always loaded → 5–7 GB (background, zero calls) push triggers xcodebuild → +4–8 GB peak (burst) Claude Code indexing large repo → +2–3 GB (interactive) Observed (24GB M4 Mac mini) Swap 0 → 2.1 GB xcodebuild link stage latency +~40% Claude Code terminal noticeably sluggish
На M4 с unified memory постоянный 8B + burst CI + интерактивное кодирование = частый swap.Смысл антипримера: scheduling — не опция, а условие при нескольких нагрузках.
Drei Lastformen: burst / interactive / background
Планировать только по часам нельзя. На Cloud Mac профили памяти разные:
| Форма | Пример | Слой | Профиль памяти | Приоритет |
|---|---|---|---|---|
| Burst | xcodebuild, Link, Simulator |
L1 Runner | пик, непредсказуемо | Наивысший — Fact не должен падать |
| Interactive | Claude Code, IDE, SSH | L3 | средний, человек у машины | высокий — inference через API, без большой модели |
| Background | Ollama Embedding, Log-Zusammenfassung | L2 | можно отложить, выгрузить | Niedrigste — muss burst weichen |
Кратко: L2 — единственный слой, который можно «выкинуть» — задачи в основном асинхронны и повторяемы.
Бюджет памяти · доли трёх workload
Ollama / Claude Code / GitHub Runner как пример компонентов; цифры иззамеров Mac mini M4(steady state, не пик компиляции):
| Компонент | Слой | Типично | Пики |
|---|---|---|---|
| macOS + системный кэш | L0 | 3–4 GB | относительно стабильно |
| Рабочая область Claude Code | L3 | 1–3 GB | inference через API, без весов модели |
| GitHub Runner job | L1 | 2–6 GB (steady) | фаза линковки +4–8 GB |
| Ollama · qwen3:8b | L2 | 5–7 GB | освобождается через ollama stop |
| Ollama · qwen3:14b | L2 | 9–13 GB | с burst легко swap 2GB+ |
| Ollama · nomic-embed-text | L2 | 0.3–0.8 GB | лёгкий background днём |
Грубо: 24GB днём «код + CI + 8B постоянно» ≈ 17 GB — ещё запас; с постоянным 14B легко >22 GB.Die Budget-Tabelle beantwortet „geht es?“; Scheduling beantwortet „wer wann Speicher nutzt“.
Модель scheduling: от слотов к порогам memory_pressure
Старт с таблицы день/ночь (режим ②); зрелее — пороги давления памяти — без «в 22:00 batch» в голове:
AI Workload Scheduler · L2-Q03 recommended rules When memory_pressure enters warn / critical (or equivalent > ~70%): → auto ollama stop qwen3:8b / qwen3:14b When memory_pressure normal (< ~50%) and idle > 10 min: → auto preload nomic-embed-text (keepalive 10m) When CI event trigger (Runner job start): → force CI mode: stop all Ollama large models, priority L1 > L3 > L2 When CI job succeeds + memory drops: → async trigger L2 batch (log summary / embedding rebuild)
Слоты — baseline; пороговый scheduling — upgrade. Малой команде: runbook + stop перед CI; затем memory_pressure-guard (§ Runbook).
Три базовых режима
Базовые стратегии с порогами:
| Режим | Как | Подходит |
|---|---|---|
| ① Лёгкий параллелизм | tagsüber nur nomic-embed-text; 8B/14B on-demand |
Mac mini 16GB, упор на код |
| ② Разделение по времени | 09–18 код+CI / 22–06 ночной batch | 24GB, плановый embedding / логи |
| ③ CI вытесняет | перед job ollama stop, затем асинхронно L2 |
частые push, высокие пики xcodebuild |
Рекомендуем: ① + ③ для всех; ② как ночной batch; guard порогов как сеть.
Разделение pipeline · L2 vs L3
Сначала зафиксировать pipeline, иначе Ollama пустует (см. L2-Q01 · типичная ошибка):
| Задача | Слой | Заметка scheduling |
|---|---|---|
| правки в репо, patch | L3 Claude Code(API) | без локальной большой модели |
| сборка, тест, архив | L1 Runner | макс. приоритет burst; stop L2 до пика |
| сводка логов при падении CI | L2 qwen3:8b |
после job или ночной batch |
| CodeGraph / RAG embedding | L2 nomic-embed-text |
можно днём (<1GB) |
Пики Runner и разнос CI
L1 Runner даёт Fact — inference не заменяет build. Минимум в CI:
# .github/workflows/ios.yml · self-hosted macOS runner - name: Enter CI mode — free memory for xcodebuild run: | ollama ps ollama stop qwen3:8b 2>/dev/null || true ollama stop qwen3:14b 2>/dev/null || true sleep 30 # wait for memory reclaim; do not start xcodebuild same second - name: Build run: xcodebuild ...
Gemessen:Auf 24GB M4 gibt ollama stop qwen3:8b освобождает 5–7 GB за ~5–15 с; при swap полный откат — минуты — поэтому stop перед CI минимум за 30 с.
Runbook: версия на 30 с und vollständiges Skript
Версия 30 с (хватит большинству)
Keine Zeit для das volle Skript? Diese drei Blöcke decken ~80 % ab:
① Перед CI (entscheidend) — in GitHub Actions oder Runner-Hook:
ollama stop qwen3:8b ollama stop qwen3:14b sleep 30
② Tagsüber — nur leichtes Embedding, keine großen Modellgewichte:
ollama run nomic-embed-text --keepalive 30m
③ Nacht — im Batch-Fenster 8B laden:
ollama run qwen3:8b # then run your log summary / embedding rebuild scripts
Полная версия (прод)
Для LaunchAgent / cron / нескольких сред сохранить как ~/bin/cloud-mac-stack-runbook.sh:
Полный runbook · подкоманды
day-start · ci-pre · ci-post · night-batch
#!/usr/bin/env bash # cloud-mac-stack-runbook.sh — L2-Q03 standard Runbook set -euo pipefail OLLAMA_HOST="${OLLAMA_HOST:-127.0.0.1:11434}" export OLLAMA_MAX_LOADED_MODELS=1 ensure_ollama() { curl -sf "http://${OLLAMA_HOST}/api/tags" >/dev/null || ollama serve & sleep 2 } ci_pre() { # before CI: force CI mode, L1 wins ollama ps || true ollama stop qwen3:8b 2>/dev/null || true ollama stop qwen3:14b 2>/dev/null || true sleep 30 } ci_post() { # after CI: restore light embedding (lowest background tier) ensure_ollama ollama run nomic-embed-text --keepalive 10m } day_start() { # login / boot: embedding only or stop all ensure_ollama ollama stop qwen3:8b 2>/dev/null || true ollama stop qwen3:14b 2>/dev/null || true ollama run nomic-embed-text --keepalive 30m } night_batch() { # night batch (cron: 0 22 * * *) ensure_ollama ollama run qwen3:8b --keepalive 6h # ./your-log-summary-or-embed-rebuild.sh } case "${1:-}" in day-start) day_start ;; ci-pre) ci_pre ;; ci-post) ci_post ;; night-batch) night_batch ;; *) echo "Usage: $0 {day-start|ci-pre|ci-post|night-batch}"; exit 1 ;; esac
Memory guard (cron каждые 5 мин или LaunchAgent): выгрузка больших моделей при давлении — минимум порогового scheduling.
#!/usr/bin/env bash # memory-guard.sh — memory_pressure threshold guard PRESSURE=$(memory_pressure 2>/dev/null | head -1 || true) if echo "$PRESSURE" | grep -qiE 'warn|critical|urgent'; then logger -t cloud-mac-stack "memory guard: stopping Ollama 8B/14B ($PRESSURE)" ollama stop qwen3:8b 2>/dev/null || true ollama stop qwen3:14b 2>/dev/null || true fi # optional: when pressure normal + no Runner job, restore embedding # if echo "$PRESSURE" | grep -qi 'normal'; then ... fi
Примеры подключения:
- GitHub Actions — erster Step
ci-pre, letzterci-post - LaunchAgent — при входе
day-start; cron 22:00night-batch - cron —
*/5 * * * * /path/memory-guard.sh
План для Mac mini 16GB
- постоянный 14B запрещён; 8B только в
night-batch - Днём только
day-start(embedding или полная остановка) - Jede CI braucht
ci-pre, ohne Ausnahme - Wenn „Desktop + 8B + Claude Code“ dauerhaft parallel laufen soll → 24GB; Scheduling hebt keine Hardware-Grenze
16GB: днём без большой модели, ночью одна модель — одна задача, перед CI всегда ci-pre. 24GB: днём embedding, 8B вразнос с CI, 14B только ночью.
Какую стратегию выбрать
| Ваш случай | Рекомендация |
|---|---|
| 24GB · мало push · в основном Claude Code | day-start + Embedding; kein Nacht-Batch |
| 24GB · tägliche CI · Log-Zusammenfassung | ci-pre/post + night-batch + Memory Guard |
| 16GB · lokales 8B nötig | nur night-batch; tagsüber Claude API |
| Ollama неделю без вызовов | zuerst L2-Q01 — Pipeline definieren |
Serie · Cloud Mac AI Stack
L2-Q03 · Слой планирования памяти — снаружи «как избежать swap на Mac mini»; внутри продолжение L2-Q01 приватного inference:
- L2-Q01 — что такое Inference (позиция)
- L2-Q03 · эта статья — слой планирования памяти (scheduling на одном хосте)
- Geplant — Model-Pinning, Health-Check 11434, Ollama-Aufruf aus CI
- Downstream — L4 Context + MCP-Scheduling (morgen L4-Q03)
Kein Ollama-Tutorial und kein reiner CI/CD-Tuning-Text — а erste Слой eines AI-Workload-Schedulers auf Apple Silicon.
Связь с опубликованными статьями
- L2-Q01 · Private Inference-Слой — L2-Position; dieser Text ist die Scheduling-Fortsetzung.
- L2-Q02 · 16GB vs 24GB — цифры swap; без повтора бенчмарка.
- L1-Q01 · Runner — höchste burst-Приоритет.
- L3 · Claude Code — interaktiver Hauptpfad.
FAQ
Ollama, Claude Code и GitHub Actions параллельно на Mac mini — будет swap?
Да, если burst-, interactive- и background-workload без приоритетов. См. § Настоящая проблема и антипример.
Ollama должен работать постоянно?
Нет. Локальный inference — планируемый ресурс: днём только nomic-embed-text, большие модели по запросу или ночным batch.
Останавливать Ollama перед CI?
Рекомендуется. См. runbook 30 с · перед CI или ci-pre в полной версии.
Claude Code и Ollama вместе?
Да. Кодинг через API; локально — веса и пики CI. stop перед CI или слоты.
OOM на Cloud Mac — нехватка RAM?
В наших сценариях большинство OOM — из-за scheduling, не абсолютный дефицит RAM. Жёсткая граница 16GB: замеры L2-Q02.
Слоты или пороги memory_pressure?
Сначала runbook на 30 с; затем memory-guard.sh (см. полный runbook ниже).
Чем эта статья отличается от L2-Q01?
Q01 — позиция Inference Service; Q03 (слой планирования памяти) — как планировать AI-workload на одном хосте.
Cloud Mac AI Stack · анонс завтра
Claude Code + MCP: GitHub, локальные файлы и API в одной цепочке
Когда слои L2 зафиксированы, следующий шаг — L4 Context: как MCP связывает GitHub, файлы репозитория и API с Claude Code.
К блогу · Cloud Mac AI Stack