团队 8 个 iOS 工程师,每天跑 200+ 次编译。之前用 M4 Max Mac 实例,128GB 内存跑 6 个 Simulator 就开始 swap。上周亚马逊云科技发布了 EC2 M3 Ultra Mac 实例——256GB 统一内存、28 核 CPU,我第一时间开了台试水。
这篇文章记录完整的开通、配置、CI/CD 集成过程,以及实际编译性能对比数据。
硬件规格一览
先看参数对比:
| 规格 | M4 Max | M3 Ultra | 提升 |
|---|---|---|---|
| CPU 核心 | 16 | 28 | 1.75x |
| GPU 核心 | 40 | 60 | 1.5x |
| Neural Engine | 16 | 32 | 2x |
| 统一内存 | 128GB | 256GB | 2x |
| 网络带宽 | 10 Gbps | 10 Gbps | — |
| EBS 带宽 | 8 Gbps | 8 Gbps | — |
说白了,M3 Ultra 就是把 M4 Max 的核心数和内存翻倍。底层跑在 AWS Nitro System 上,网络和存储带宽保持 10 Gbps / 8 Gbps。
开通步骤
EC2 Mac 实例需要先申请 Dedicated Host,这是苹果的许可要求。
第一步:申请 Dedicated Host
aws ec2 allocate-hosts \--instance-type mac3-ultra.metal \--availability-zone us-east-1a \--quantity 1 \--tag-specifications 'ResourceType=dedicated-host,Tags=[{Key=Name,Value=ios-ci-host}]'
返回的 HostId 记下来,后面启动实例要用。
第二步:选 AMI
aws ec2 describe-images \--owners amazon \--filters "Name=name,Values=amzn-ec2-macos-15*" \"Name=architecture,Values=arm64_mac" \--query 'Images | sort_by(@, &CreationDate) | [-1].ImageId' \--output text
我这边拿到的是 macOS 15.x 的最新 AMI。建议用 macOS 14+ 以获得 Xcode 16 支持。
第三步:启动实例
aws ec2 run-instances \--instance-type mac3-ultra.metal \--image-id ami-0xxxxxxxxxxxxxxxx \--key-name my-ios-key \--placement "HostId=h-0xxxxxxxxxxxxxxxx" \--security-group-ids sg-0xxxxxxxx \--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":500,"VolumeType":"gp3","Iops":16000,"Throughput":1000}}]'
几个注意点:
instance-type必须是mac3-ultra.metal,没有虚拟化选项- EBS 建议 500GB+ gp3,iOS 项目加上 DerivedData 很吃空间
- Dedicated Host 最低租期 24 小时,别开了立刻关
第四步:SSH 连接并安装 Xcode
ssh -i my-ios-key.pem ec2-user@<public-ip># 安装 Xcode CLI Tools
sudo xcode-select --install# 如果需要完整 Xcode,用 xcodes 工具
brew install xcodes
xcodes install 16.2
配置 CI/CD 流水线
我用的是 Jenkins + EC2 Mac 实例做 agent。核心配置:
Jenkinsfile 示例
pipeline {agent { label 'mac-m3-ultra' }environment {DEVELOPER_DIR = '/Applications/Xcode-16.2.app/Contents/Developer'}stages {stage('Checkout') {steps {checkout scm}}stage('Build') {steps {sh '''xcodebuild -workspace MyApp.xcworkspace \-scheme MyApp \-destination "platform=iOS Simulator,name=iPhone 16 Pro" \-derivedDataPath ./DerivedData \-parallelizeTargets \-jobs 24 \clean build'''}}stage('Test - Parallel Simulators') {steps {sh '''xcodebuild test \-workspace MyApp.xcworkspace \-scheme MyApp \-destination "platform=iOS Simulator,name=iPhone 16 Pro" \-destination "platform=iOS Simulator,name=iPhone 15" \-destination "platform=iOS Simulator,name=iPad Pro 13-inch (M4)" \-parallel-testing-enabled YES \-maximum-parallel-testing-workers 12 \-derivedDataPath ./DerivedData \-resultBundlePath ./TestResults'''}}}
}
关键参数:-maximum-parallel-testing-workers 12。M3 Ultra 的 28 核 CPU 和 256GB 内存能轻松撑住 12 个并行 Simulator,之前 M4 Max 开到 6 个就顶了。
实际性能对比
我跑了三组测试(同一个 50 万行 Swift 项目):
| 场景 | M4 Max | M3 Ultra | 提升 |
|---|---|---|---|
| Clean Build | 8m 42s | 5m 15s | 40% |
| Incremental Build | 1m 30s | 58s | 35% |
| 12 并行 Simulator 测试 | OOM 崩溃 | 18m 22s | ∞ |
| 6 并行 Simulator 测试 | 32m 10s | 16m 45s | 48% |
12 个并行 Simulator 是 M3 Ultra 的杀手场景。M4 Max 的 128GB 根本扛不住,直接 OOM。M3 Ultra 的 256GB 统一内存让每个 Simulator 分到 ~20GB,绰绰有余。
CoreML 模型训练加速
如果你的 App 有端侧 ML 模型,M3 Ultra 的 32 核 Neural Engine 也很有用:
# 转换并优化 CoreML 模型
python3 -m coremltools.converters.convert \--model ./model.onnx \--output ./Model.mlpackage \--compute-units ALL# 在 M3 Ultra 上跑 benchmark
xcrun coremlbenchmark ./Model.mlpackage --compute-units cpuAndNeuralEngine
32 核 Neural Engine 跑推理比 M4 Max 的 16 核快接近一倍,模型验证环节省时间。
成本考量
Mac Dedicated Host 按小时计费,最低 24 小时起。M3 Ultra 的价格比 M4 Max 贵约 80%。
省钱策略:
- 共享 Host:多个 CI job 排队用同一台,别开多台
- 非工作时间释放:周末和夜间释放 Host(注意 24h 最低租期)
- Savings Plans:如果长期用,1 年期 Compute Savings Plan 能省 40%
# 释放 Dedicated Host(24h 后)
aws ec2 release-hosts --host-ids h-0xxxxxxxxxxxxxxxx
什么时候该上 M3 Ultra
- ✅ 团队 5+ iOS 工程师,每天编译次数 > 100
- ✅ 项目代码量 > 30 万行 Swift
- ✅ 需要跑 8+ 并行 Simulator 做 UI 测试
- ✅ 有 CoreML 模型训练/验证需求
- ❌ 小团队 1-2 人,M4 Max 够用
- ❌ 只跑单元测试不跑 UI 测试,内存压力小
小结
M3 Ultra Mac 实例解决的核心问题就一个:内存。256GB 统一内存让并行 Simulator 数量翻倍,编译速度提升 35-48%。如果你的团队被 CI/CD 编译时间卡脖子,值得试试。
开通文档:https://aws.amazon.com/ec2/instance-types/mac/
踩坑提醒:第一次开 Dedicated Host 可能需要提工单提额度,别到项目赶工期了才发现开不了。
