Вывод сразу: для большинства «крупных iOS-проектов» (много модулей, смесь CocoaPods/SPM, ежедневные пуши в main) Mac mini M4 10 ядер + 24 ГБ unified memory в 2026 году — лучший узел сборки по цене/качеству: холодный полный Archive P50 около 11–14 минут, инкрементальная сборка 2–4 минуты; чистый CI Runner без GUI часто укладывается в 16 ГБ, но параллельные симуляторы лучше ограничивать.
Четыре реально тяжёлых этапа: ① параллельный swift-frontend по target’ам; ② финализация LTO / bitcode линкером; ③ случайное чтение DerivedData и ModuleCache; ④ swap и троттлинг при нехватке памяти.
Типичная ошибка: винить M4 в медленной сборке, но очищать диск на каждом CI job — постоянная DerivedData часто даёт больше, чем переход на M5. Модель эксплуатации: ускорение self-hosted runner.
Когда в команде 500+ Swift-файлов, 80+ pod’ов и 30+ CI-запусков в день, закупки спрашивают: хватит ли Mac mini M4? Нужен M4 Pro? Ждать M5? На bare-metal кластерах M4 Nuvcloud две недели сравнивали три реальных клиентских проекта (анонимизированы): одинаковые параметры xcodebuild, стабильный Xcode 16.4, одна стратегия пути DerivedData. Ниже — воспроизводимая методика и выборочные данные, не лабораторный бенчмарк; проверяйте на своём репозитории.
1) Определение: что такое «крупный iOS-проект»
Единого стандарта «крупности» нет. Мы делим клиентов Nuvcloud на четыре уровня; данные ниже в основном для уровня L:
| Уровень | Типичный профиль | Холодный Archive P50 (M4 16 ГБ) |
|---|---|---|
| S · малый/средний | <150 Swift-файлов, в основном SPM, без тяжёлых C++ pod’ов | 4–6 min |
| M · средний | 150–400 файлов, CocoaPods + 2–3 Extension | 7–10 min |
| L · крупный | 400+ файлов, 10+ модулей / несколько target’ов, гибрид Flutter/RN | 11–16 min |
| XL · очень крупный | Monorepo, white-label приложения, полный LTO | 18–28 min (разбить проект или добавить Runner) |
Для L или XL при одновременной индексации Xcode + UI-тестах на Simulator узким местом чаще становится память, а не модель CPU — это недооценивают чаще, чем смену поколения чипа.
2) Чип M4: для сборки важны параллелизм CPU и пропускная способность памяти, не GPU
Mac mini M4 (2024, базовая): CPU 10 ядер (4 performance + 6 efficiency), GPU 10 ядер, unified memory от 16 ГБ (опционально 24 ГБ / 32 ГБ). Для xcodebuild:
- Performance-ядра несут
swift-frontendи clang — Xcode по умолчанию загружает доступные performance-ядра; efficiency-ядра полезны для prefetch I/O и фоновой индексации. - Unified memory = куча компилятора + working set линкера + ModuleCache — 16 ГБ часто хватает при «только сборка» без симулятора; с
xcodebuild testи Simulator iOS 18 кривая памяти резко растёт. - Последовательная скорость SSD редко узкое место, случайный I/O — да — в DerivedData десятки тысяч мелких файлов; NVMe Mac mini достаточен для крупных проектов, но при заполнении диска >85 % P99 заметно ухудшается.
- GPU и Neural Engine почти не влияют на чистую компиляцию; конвертация Core ML и сборка Metal-шейдеров используют GPU.
Относительно M3 M4 даёт ~15 % в Geekbench single-core; при уже хорошо распараллеленном link ощущается скорее как 10–20 %. Руководство Apple по эффективности сборки по-прежнему рекомендует модульное разбиение — железо не лечит циклические зависимости.
3) Методика: три машины, два проекта, одна команда
Оборудование (от сети, macOS 15.5, автосон выключен):
- A: Mac mini M4 10 ядер / 24 ГБ / SSD 512 ГБ (Nuvcloud bare metal, ЦОД)
- B: Mac mini M2 Pro 10 ядер / 16 ГБ / SSD 512 ГБ (клиент, офис)
- C: MacBook Pro M3 Pro 11 ядер / 18 ГБ / 1 ТБ (клиент, от сети)
Образцы проектов:
- Proj-α (уровень L): UIKit + SwiftUI, 86 CocoaPods, один scheme Archive, ~520 Swift-файлов
- Proj-β (L+): модульная структура + 2 Extension + модуль Flutter, ~680 файлов Swift/ObjC
Единая команда (Release / device / без тестов):
xcodebuild -workspace App.xcworkspace -scheme App -configuration Release -destination 'generic/platform=iOS' -derivedDataPath ~/Build/DerivedData clean archive (холодный старт с clean; инкрементально без clean и тот же путь DerivedData)По 5 прогонов, P50, первый исключается (прогрев кэша диска). Температура и сеть не влияют на локальный этап сборки, но влияют на pod install — цифры ниже без скачивания зависимостей.
4) Холодный полный Archive: где выигрывает M4
Proj-α холодный старт P50 (секунды → минуты):
| Машина | compile | link | Итого |
|---|---|---|---|
| M4 24 ГБ (A) | 548 s | 142 s | ~11.5 min |
| M2 Pro 16 ГБ (B) | 672 s | 178 s | ~14.2 min |
| M3 Pro 18 ГБ (C) | 598 s | 155 s | ~12.6 min |
Proj-β (с Flutter) увеличивает разрыв: M4 P50 ~15.8 min, M2 Pro ~20.4 min. ios/Flutter и нативные target’ы Xcode конкурируют за CPU; 24 ГБ держат M4 практически без swap, у M2 Pro 16 ГБ на этапе link бывает memory pressure, P99 до 24 min.
5) Инкрементальная сборка: настоящая сильная сторона M4
Около 80 % ежедневных сборок меняют несколько файлов. При сохранённой DerivedData, Proj-α, изменён 1 Swift-файл, инкрементальный Archive P50:
| Машина | Инкремент P50 | Примечание |
|---|---|---|
| M4 24 ГБ | 2 min 10 s | стабильно |
| M2 Pro 16 ГБ | 2 min 45 s | иногда полная пересборка (границы модулей) |
| M3 Pro 18 ГБ | 2 min 22 s | стабильно |
Смена мажорной версии Xcode или SWIFT_VERSION инвалидирует ModuleCache — одна из причин, почему CI замедляется в сезон WWDC. Для CI сохранять DerivedData между job’ами эффективнее смены M5; тот же M4: ephemeral disk P50 28 min, persistent disk P50 9 min (см. гайд по ускорению).
6) 16 ГБ / 24 ГБ / 32 ГБ: как выбрать
| Конфигурация | Подходящие сценарии | Риски для крупных проектов |
|---|---|---|
| 16 ГБ | чистый CLI CI Runner; без Simulator; один job | параллельный xcodebuild test + Archive → swap; подтормаживает индексация Xcode GUI |
| 24 ГБ | общий Runner команды + редкий VNC; 10–30 сборок/день | Proj-β с 2 Simulator одновременно всё ещё впритык |
| 32 ГБ | monorepo, параллельные UI-тесты, постоянный Instruments | выше стоимость; убывающая отдача только для compile |
При росте цен на память в 2026 24 ГБ — sweet spot для уровня L. При бюджете 16 ГБ разнесите UI-тесты и Archive на разные runner label в workflow — см. разделение beta/production runner.
7) Параллелизм: задействовать все 10 ядер M4
По умолчанию xcodebuild читает доступные ядра, но крупные проекты часто тормозят из-за:
SWIFT_COMPILATION_MODE = wholemoduleрезко увеличивает память на больших target’ах — дробление по модулям дешевле, чем больше RAM.- Отключить лишний
DEBUG_INFORMATION_FORMAT = dwarf-with-dsymв CI Release (в локальном Debug оставить). - Явно задать
-jobs: в ЦОД часто-jobs 8(2 ядра системе и sshd), чтобы избежать OOM. - CocoaPods
use_frameworks! :linkage => :staticсокращает время динамической линковки, но удлиняет первую сборку — компромисс команды.
Если в Activity Monitor только 4–5 процессов swift-frontend на полной нагрузке, чаще виноваты сериальные зависимости target’ов или один гигантский Swift-файл — смотрите Build Timeline (Xcode 16+), а не обвиняйте M4.
8) Две модели нагрузки: dev-машина vs CI 7×24
Модель A · удалённая сборка (см. прощай, медленный Xcode): тонкий локальный ноутбук, SSH на M4 для xcodebuild. Важны инкрементальная задержка и плавный VNC — 24 ГБ комфортнее.
Модель B · self-hosted CI: GitHub Actions / GitLab Runner на M4, десятки запусков в день. Важны постоянная DerivedData, ресурс SSD, очередь job’ов. 16 ГБ часто хватает; узкое место — очередь, не чип.
Кэш Flutter на трёх платформах: Flutter iOS CI. Пайплайн Fastlane / TestFlight: гайд self-hosted CI.
9) Когда брать M4 Pro, второй Runner или масштабировать в облаке
При этих сигналах добавить машины выгоднее, чем добавлять ядра:
- Холодный P50 стабильно >18 min и нельзя быстро разбить модули — governance уровня XL, а не только Pro-чип.
- Очередь PR на одном Runner >15 min — второй M4 16 ГБ горизонтально лучше одного M4 Pro.
- 3+ параллельных UI-теста на Simulator — 32 ГБ или отдельная тестовая машина; разделить label compile и test.
- Ограничены закупка, офисное электричество, ops — облачный bare-metal M4 посуточно; TCO runner’ов: сравнение шести регионов.
M4 Pro (от 12 CPU-ядер) на Proj-α при холодном старте был лишь на ~8 % быстрее при заметно более высокой цене — без видеотранскодинга и локального LLM: для iOS-сборки важнее число runner’ов.
10) Частые вопросы
Справится ли Mac mini M4 16 ГБ с крупным iOS-проектом? Да, как выделенный CI-узел; не открывайте одновременно Xcode GUI + два Simulator. Для удалённой разработки лучше 24 ГБ.
Насколько быстрее GitHub-hosted macOS? Только сегмент xcodebuild часто 10–20 %; полная цепочка hosted P50 25–45 min из-за очереди и холодного кэша, self-hosted M4 8–12 min с постоянной DerivedData.
Стоит ждать Mac mini M5? Если узкое место — ephemeral CI-диск или swap на 16 ГБ, M5 мало поможет. Если проект растёт >30 % файлов в год, переоцените осенью; сейчас M4 + постоянные runner’ы практичнее. Контекст: почему M5 не показали на WWDC 26.
Заменит ли macOS VM bare metal? Подпись, планирование performance-ядер, Metal/Simulator в общей VM ненадёжны. Для серьёзного pipeline — bare-metal Mac mini; сравнение: VM vs реальное железо.
Тот же M4—from coffee break к ожиданию в Slack
48-часовой дневной тариф на вашем repo → Цены M4 · Runner: self-hosted