Почему локальные сборки на MacBook замедляются
Многие инди-разработчики и небольшие команды работают на MacBook Air или базовом MacBook Pro —
удобно и экономно по энергии, но часто с 8 или 16 ГБ RAM. При открытом Xcode, Simulator, десятке вкладок Chrome,
Slack и Preview физической памяти для swift-frontend и ld остаётся мало.
macOS начинает вытеснять DerivedData и кэши индекса на SSD. Кажется, что «сборка просто на пару минут дольше»,
но на деле пропускная способность памяти уходит в swap, и каждая следующая инкрементальная сборка становится чуть тяжелее.
Часто упускают из виду термальное ограничение. Охлаждение ноутбука имеет предел; после 8–15 минут полной сборки частота CPU может упасть на 15–25 %, а шум вентиляторов мешает видеозвонкам. Mac mini в стойке дата-центра охлаждается стабильно — идеален как выделенная машина сборки, пока ноутбук остаётся свободным для редактирования и созвонов.
Эта статья отвечает на конкретный вопрос: на масштабе реалистичного проекта, сколько выигрывает перенос компиляции на выделенный узел M4 SpinMac? Какова цена? Когда облако не стоит усилий?
Тестовое окружение и методика
Для воспроизводимости: одна версия Xcode, одна процедура очистки DerivedData,
замер через xcodebuild и /usr/bin/time -l, чтобы исключить индексацию GUI и фоновые задачи.
Перед каждой серией: rm -rf ~/Library/Developer/Xcode/DerivedData/*, закрыты лишние приложения.
Локально A: MacBook Air M2 · CPU 8 ядер · 8 ГБ унифицированной памяти · SSD 256 ГБ · macOS 15 Sequoia.
Локально B (контроль): MacBook Pro 14" M1 Pro · CPU 10 ядер · 16 ГБ унифицированной памяти · SSD 512 ГБ · тот же OS.
Облако: SpinMac Mac mini M4 · CPU 10 ядер · 16 ГБ унифицированной памяти · SSD NVMe 256 ГБ · выделенный канал 1 Gbps (узел Сингапур).
Toolchain: Xcode 16.4, Command Line Tools совпадают.
Сэмплирование: memory_pressure для swap; powermetrics каждые 5 с для частоты CPU; уровень шума вентилятора на расстоянии 30 см от корпуса.
Тестовое приложение: внутреннее SwiftUI «PulseTrack» — около 82 000 строк Swift, четыре target (основное приложение, Share Extension, Widget Extension, Watch App), шесть зависимостей SPM (включая Alamofire, Kingfisher). Средний размер для App Store — не гигантский монорепозиторий, но достаточный, чтобы нагрузить машину с 8 ГБ.
Три сценария сборки и команды
Три типичные ситуации: от ежедневной итерации до публикации в App Store.
Сценарий 1: полный clean build (Debug)
Имитирует первый checkout в CI или холодный старт после смены ветки:
xcodebuild -scheme PulseTrack -configuration Debug -destination 'platform=iOS Simulator,name=iPhone 16 Pro' clean build CODE_SIGNING_ALLOWED=NO
Подпись отключена, чтобы изолировать компиляцию. Три прогона на машину, берётся медиана.
Сценарий 2: инкрементальная сборка одного файла
Изменение одного Swift-файла (~40 строк UI-логики), затем сборка без clean. Самое частое действие в работе, очень чувствительно к свободной RAM и состоянию индекса.
Сценарий 3: Release Archive
Полный Archive с Distribution-сертификатом, оптимизацией (-O) и без bitcode.
Максимальная длительная нагрузка на CPU — типичный сценарий троттлинга на ноутбуке.
Локальный B (M1 Pro 16 ГБ) — контрольная группа «уже неплохой ноутбук», чтобы отделить выигрыш M4 в облаке от поколения чипа
и от того, что машина только собирает, не деля RAM с остальным.
Облачные замеры по SSH; сетевая задержка не входит в таймер (исходники предварительно синхронизированы через rsync).
Сравнение времени: ключевые цифры
Медиана трёх серий ниже. M4 в облаке лидирует во всех трёх случаях; максимальный разрыв на Archive — проходы оптимизации требуют устойчивой нагрузки, а охлаждение в стойке удерживает частоты.
| Сценарий | MacBook Air M2 · 8 ГБ | MacBook Pro M1 Pro · 16 ГБ | SpinMac M4 · 16 ГБ |
|---|---|---|---|
| Полный clean build (Debug) | 11′42″ | 7′08″ | 5′18″ |
| Инкремент одного файла | 48″ | 26″ | 17″ |
| Release Archive | 18′35″ | 11′20″ | 8′12″ |
| Пик использования swap | 2,8 ГБ | 0,4 ГБ | 0 ГБ |
| Шум вентилятора при сборке (пик) | 46 дБ | 41 дБ | (дата-центр — н/д) |
На Air M2 заметный swap появляется примерно на шестой минуте clean build
(system-wide memory free percentage около 4 % в memory_pressure).
Суммарная загрузка CPU процессов swift-frontend падает с ~680 % до ~420 % — дело не в «тормозящем Xcode», а в подкачке ядра.
M4 в облаке держал все десять ядер на 85–92 % без зафиксированного троттлинга.
Локальный M1 Pro 16 ГБ в полном clean build был лишь ~34 % медленнее облачного M4 — намного меньше, чем коэффициент 2,2 у Air 8 ГБ. Объём памяти часто становится узким местом раньше поколения чипа. При 16 ГБ локально смысл облака смещается от «сырой скорости» к «выделенная сборка без помех в повседневной работе».
Параллельная нагрузка: Simulator открыт во время сборки
Предыдущая таблица — «чистый стол». На практике Simulator для превью UI часто работает во время полной пересборки (смена конфигурации, очистка DerivedData и т.д.).
При такой комбинированной нагрузке Simulator на Air M2 нередко падает ниже 20 ips, а clean build растёт с 11′42″ до 14′28″. M1 Pro: 8′45″ — терпимо. M4 в облаке с превью Simulator по VNC: лишь ~40 с больше (5′58″), потому что обе нагрузки получают RAM и CPU, не деля 8 ГБ.
После трёх clean build DerivedData на Air достигает 4,7 ГБ — приемлемо на SSD 256 ГБ, но при 8 ГБ RAM кэш индекса конкурирует с артефактами сборки. На облачных узлах доступно расширение SSD +1 ТБ (от $2,5/день) для команд, хранящих несколько кэшей веток.
Ошибки, из‑за которых сравнение теряет смысл
Если эти детали расходятся, результат может отличаться на 30 % и больше:
-
01
Сборка до завершения индексации
При первом открытии фоновая индексация может съесть 2–4 ГБ. Дождитесь окончания или используйте
xcodebuild, чтобы убрать шум GUI. -
02
Разные настройки Build System
С обеих сторон: New Build System и одинаковый
COMPILER_INDEX_STORE_ENABLE, иначе инкрементальное время несопоставимо. -
03
Синхронизация исходников в облако
rsync --deleteдля согласованного workspace. Не собирайте с смонтированного по сети FUSE-диска — сетевой I/O станет невидимым узким местом. -
04
Архитектура симулятора
Симулятор Apple Silicon по умолчанию arm64. Сборка ещё и под x86_64 на одной машине может почти удвоить время.
Некоторые VPS-продавцы предлагают виртуализированный или перегруженный macOS без полного toolchain Xcode и стабильной квоты CPU. Мы намеренно использовали выделенные физические Mac mini M4 у SpinMac — clean build на виртуализации часто «плавает» на 40–60 % и плохо подходит как эталон.
Удалённый workflow: разработка локально, сборка в облаке
При 8 ГБ или ноутбуке 16 ГБ между созвонами и разработкой не обязательно продавать машину ради Mac Studio. Прагматичный путь: вынести сборку Xcode и нагрузку Simulator в облако, редактор и Git оставить локально.
Типичная ситуация: демо в 15:00, коллега пушит ветку с полной пересборкой, вентиляторы на максимуме, Zoom дёргается — это не вопрос навыков, а делёжки ресурсов. Облачный узел M4 от $21,2/день: включить на неделю релиза, выключить потом — часто дешевле апгрейда железа.
-
01
Поднять узел SpinMac
Выберите регион (Сингапур / Япония Токио / Корея Сеул / Гонконг, Китай / США Восток). SSH и VNC за 1–5 минут. См. центр помощи.
-
02
Синхронизировать код и зависимости
Первый перенос:
rsync -avz --exclude DerivedData ./ user@host:~/PulseTrack/. На узле:xcodebuild -resolvePackageDependenciesдля SPM. -
03
Редактировать локально или по SSH, собирать удалённо
VS Code Remote SSH или Cursor Remote; команды сборки в SSH-сессии. Превью UI через браузерный VNC и Simulator при необходимости.
-
04
Подключить как CI runner (опционально)
Тот же узел как self-hosted runner GitHub Actions. Шаги в руководстве CI/CD Xcode на облачном Mac.
Пять регионов дают выделенный 1 Gbps и публичный IPv4.
Из офиса в Москве до Сингапура: инкрементальный rsync ~120 изменённых файлов за 4–8 секунд —
пренебрежимо для инкрементальных workflow. Для APAC — Сингапур или Япония; для рынка США — США Восток.
Стоимость и уместность: когда облако оправдано
| Ваша ситуация | Рекомендация | Роль облака |
|---|---|---|
| MacBook Air 8 ГБ, постоянный swap | Сборки + Simulator на M4 в облаке | Посуточная аренда, недели релиза |
| 16 ГБ локально, OK, но вентиляторы мешают созвонам | Full / Archive в облаке, инкремент локально | Гибридный workflow, меньше шума |
| Команда 3–10 человек, одна машина сборки | Постоянный M4 в облаке + CI runner | $106,1/мес., выделенно, без очереди |
| Mac Studio 64 ГБ, узких мест нет | Облако опционально | Кластер TB5 для параллельных Archive |
Быстрый расчёт: clean build с 12 до 5 минут, шесть сборок в день → ~42 минуты экономии. По часовой ставке разработчика полдня может окупить $21,2 узла — не считая вентиляторов, качества звонка и батареи. Облако не заменяет ноутбук: оно даёт сборкам выделенное физическое железо без прерываний.
Чтобы автоматизировать pipeline, см. руководство по GitHub Actions и Jenkins. Параллельные Archive на нескольких машинах: бенчмарк кластера Thunderbolt 5.
Выделенный M4 для сборок Xcode — без отъёма RAM у ноутбука
Выделенный узел SpinMac Mac mini M4: 16 ГБ унифицированной памяти, полный Xcode, доступ SSH / VNC, пять регионов, от $21,2/день без долгосрочных обязательств.