编程进阶网 编程进阶网
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机组成原理
  • 操作系统原理
  • 网络协议原理
  • 数据库系统原理
  • 序卷导读
  • 数据本质
  • 运行模型
  • 并发设计
  • 内存真相
  • 交互系统
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 体系建设
  • 代码品质
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 性能优化
  • 数据结构导论
  • 线性结构详解
  • 树哈希结构论
  • 容器设计实战
  • 经典算法思想
  • 工程案例剖析
  • 算法题库精练
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript案例
  • JavaScript高级
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 毛选解读
  • 自我精进
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机组成原理
  • 操作系统原理
  • 网络协议原理
  • 数据库系统原理
  • 序卷导读
  • 数据本质
  • 运行模型
  • 并发设计
  • 内存真相
  • 交互系统
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 体系建设
  • 代码品质
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 性能优化
  • 数据结构导论
  • 线性结构详解
  • 树哈希结构论
  • 容器设计实战
  • 经典算法思想
  • 工程案例剖析
  • 算法题库精练
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript案例
  • JavaScript高级
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 毛选解读
  • 自我精进
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

    • README
    • ObjC编程入门

    • Swift编程入门

    • 专栏博客

      • iOS系统架构概览
        • 1. 案例引入
          • 1.1 冷启动卡在白屏
          • 1.2 顺藤摸到根因
          • 1.3 我们要回答什么
        • 2. 架构概览
          • 2.1 五层总图
          • 2.2 为什么这么分层
        • 3. XNU内核与Mach
          • 3.1 Mach微内核设计
          • 3.2 BSD层的角色
          • 3.3 内存管理与VM
        • 4. dyld与Mach-O加载
          • 4.1 Mach-O文件结构
          • 4.2 dyld加载流程
          • 4.3 动态库与共享缓存
        • 5. SpringBoard与应用生命周期
          • 5.1 SpringBoard的角色
          • 5.2 App五种状态切换
          • 5.3 后台执行机制
        • 6. 沙盒与安全模型
          • 6.1 沙盒的三层隔离
          • 6.2 签名与权限控制
        • 7. 案例回溯与设计哲学
          • 7.1 案例真相揭晓
          • 7.2 设计哲学回扣
      • Runtime消息转发机制
      • RunLoop运行循环揭秘
      • UIView生命周期与渲染
      • 事件响应与手势识别
      • AutoLayout布局系统
      • 自定义View绘制实践
      • CoreAnimation动画实战
      • ViewController容器管理
      • 转场动画与导航设计
      • 网络层架构设计
      • 数据持久化方案选型
      • 多线程与GCD实践
      • 内存管理与ARC原理
      • Block底层原理与应用
      • KVO与KVC实现机制
      • 性能优化与启动加速
      • 组件化与模块设计
      • 安全加密与逆向防护
      • 跨平台与混编方案
  • Web开发和进阶

  • Linux应用开发

  • IoT智能硬件开发

  • Apps
  • iOS开发和进阶
  • 专栏博客
杨充
2026-06-20
目录

iOS系统架构概览

# iOS系统架构概览

精简篇 | Mach内核→CoreOS→CoreServices→Media→CocoaTouch五层架构,以及iOS启动流程与dyld加载。

# 目录介绍

  • 1. 案例引入
    • 1.1 冷启动卡在白屏
    • 1.2 顺藤摸到根因
    • 1.3 我们要回答什么
  • 2. 架构概览
    • 2.1 五层总图
    • 2.2 为什么这么分层
  • 3. XNU内核与Mach
    • 3.1 Mach微内核设计
    • 3.2 BSD层的角色
    • 3.3 内存管理与VM
  • 4. dyld与Mach-O加载
    • 4.1 Mach-O文件结构
    • 4.2 dyld加载流程
    • 4.3 动态库与共享缓存
  • 5. SpringBoard与应用生命周期
    • 5.1 SpringBoard的角色
    • 5.2 App五种状态切换
    • 5.3 后台执行机制
  • 6. 沙盒与安全模型
    • 6.1 沙盒的三层隔离
    • 6.2 签名与权限控制
  • 7. 案例回溯与设计哲学
    • 7.1 案例真相揭晓
    • 7.2 设计哲学回扣

# 1. 案例引入

# 1.1 冷启动卡在白屏

去年团队上线一个新版本,测试环境一切正常。但灰度期间收到大量用户反馈:App 冷启动卡在白屏 5-8 秒才进首页,热启动正常。Xcode Organizer 里看到主线程在启动阶段卡在 dyld 相关调用上。

Time Profiler 采样(启动阶段):
 79.2%  dyld::ImageLoader::recursiveInitialization
 12.1%  _dyld_start
  5.3%  libSystem_initializer
  3.4%  main

main() 函数只占了 3.4%,意味着 96% 的启动时间都花在了 main 之前——也就是 dyld 加载动态库的阶段。

我们做了什么?查了 MachOView,发现工程链入了 37 个动态库,其中 12 个是第三方 SDK,每个在 +load 方法里做了大量初始化操作。这 37 个库的加载、符号绑定、+load 执行——全部挤在 main() 之前串行完成。

# 1.2 顺藤摸到根因

沿着这条线往下挖:

  • 假设 1:是不是 dyld 本身有性能问题?——不是,dyld 3 已经做了大量优化(启动闭包),是库太多导致的。
  • 假设 2:能不能把部分库延迟加载?——iOS 不支持 dlopen 延迟加载系统库,但自建动态库可以通过 dlopen 在用到时才加载。
  • 假设 3:+load 执行的耗时怎么来的?——Xcode 的 Environment Variables 里设置 DYLD_PRINT_STATISTICS,发现 12 个 +load 方法合计耗时 3.2 秒。
  • 假设 4:为什么热启动没问题?——热启动时 dyld 的共享缓存(dyld shared cache)还在内存里,直接跳过加载步骤。
  • 假设 5:App 启动到底经历了什么?——从用户点图标到 main(),中间隔着一整套 iOS 系统流程。

这个看似 "库太多" 的工程问题,背后藏着一整套 iOS 系统架构的知识:

① iOS 系统分几层?App 跑在哪一层?           → 第 2 章
② Mach-O 是什么格式?为什么不是 ELF?        → 第 4 章
③ dyld 怎么加载动态库?为什么有共享缓存?      → 第 4 章
④ 从点图标到 main() 发生了什么?             → 第 5 章
⑤ 沙盒是怎么隔离 App 的?                   → 第 6 章
⑥ XNU 内核的 Mach 和 BSD 分别管什么?        → 第 3 章
⑦ iOS 后台机制为什么杀的这么狠?             → 第 5.3 节

# 1.3 我们要回答什么

这个启动优化案例就是本篇的主线案例。每讲完一层架构就解开一两个问号,最后在第 7 章把案例剖开,给出三种优化方案。

📌 本篇定位:这是整个 iOS 专栏的地基篇。后面 19 篇讲的 Runtime、RunLoop、View 渲染、Block 底层、内存管理——本质都是 "在这张 iOS 架构地图上的某一块里发生的事"。读完本篇,再看任何 iOS 技术话题,都能立刻回答:"它在哪一层"。

# 2. 架构概览

# 2.1 五层总图

iOS 的系统架构自下而上分为五层(从硬件到用户):

┌──────────────────────────────────────────────────────────────┐
│                    Cocoa Touch 层                             │
│   UIKit · SwiftUI · PushKit · MapKit · MessageUI · ...       │  ← App 直接调用的 API
├──────────────────────────────────────────────────────────────┤
│                      Media 层                                 │
│   Core Animation · Core Graphics · Core Audio · AVFoundation  │  ← 音视频、2D/3D渲染
│   Metal · OpenGL ES · Core Image · Core Text · SpriteKit      │
├──────────────────────────────────────────────────────────────┤
│                   Core Services 层                            │
│   Foundation · Core Data · Core Location · CFNetwork         │  ← 数据存储、网络、定位
│   StoreKit · WebKit · CloudKit · Core Motion                  │
├──────────────────────────────────────────────────────────────┤
│                     Core OS 层                                │
│   libSystem (libc, libm, libpthread) · Accelerate · Security  │  ← 系统调用入口
│   System Configuration · libdispatch (GCD) · libobjc          │
├──────────────────────────────────────────────────────────────┤
│                   Kernel & Drivers 层                         │
│   XNU Kernel (Mach + BSD + IOKit) · Sandbox · File System    │  ← 进程管理、内存、IO
│   Drivers · TCP/IP · Virtual Memory · Power Management        │
└──────────────────────────────────────────────────────────────┘

关键边界:

  • Cocoa Touch 层以上:你的 App,用户看得见的 UI 和交互逻辑
  • Core OS 层以下:内核态,App 通过 syscall 间接访问
  • Media / Core Services:桥接层——上层调 API,下层调系统调用

# 2.2 为什么这么分层

iOS 分层不是 "画图好看",每一层解决一类独立问题:

分层理由 说明
权限隔离 内核层拥有最高权限;Core OS 提供系统调用的安全入口;上层 App 受沙盒限制
复用与演进 macOS / iOS / watchOS / tvOS 共享 Core OS + Core Services 两层,各自的 Cocoa Touch 层不同
性能分层 Metal 直达 GPU 驱动(跳过中间层),比 OpenGL ES 少两层调用;这就是为什么 Metal 比 OpenGL 快
向后兼容 iOS 大版本升级时,底层重构不影响 UIKit API —— App 不用改代码就能跑在新系统上

对比 Android:Android 的 HAL(硬件抽象层)是单独一层,iOS 把它藏在 IOKit 里,对外不可见。这是 iOS "封闭"的根源。

# 3. XNU内核与Mach

# 3.1 Mach微内核设计

iOS 的 XNU 内核("X is Not Unix")由两个内核融合而成:Mach(来自 CMU)和 BSD(来自 FreeBSD)。

Mach 负责最底层的"硬骨头":

Mach 职责 具体内容
进程与线程管理 每个 App 是一个 Mach 进程(task),内部可以有多个 thread
虚拟内存 所有进程看到的地址都是虚拟地址,通过 MMU 翻译到物理地址
IPC 通信 Mach Port —— iOS 上所有跨进程通信的基础(XPC、App Group 都建立在它之上)
时钟与调度 时间片轮转、优先级调度、实时线程

Mach 的设计哲学是 "最小内核"——Mach 本身只做进程/线程/内存/IPC 四件事,其它(文件系统、网络栈、用户权限)全部交给 BSD 层。这让内核更容易验证正确性,也更容易移植到 Apple Watch 这类极低功耗设备。

# 3.2 BSD层的角色

BSD 层套在 Mach 之上,提供 POSIX 兼容的 Unix 接口:

App 代码:  open("file.txt", O_RDONLY)
              │
              ▼
BSD 层:    syscall(SYS_open, ...)     ← POSIX 系统调用
              │
              ▼
Mach 层:   mach_vm_map(...)          ← 最终通过 Mach 操作虚拟内存

BSD 层对开发者最重要的三件事:

  1. 文件系统:HFS+/APFS 的管理,App 沙盒的文件隔离(第 6 章)
  2. 网络栈:BSD Socket → TCP/IP → Wi-Fi/蜂窝驱动(NSURLSession 底层最终在这)
  3. 权限模型:root/mobile/_wireless 等多用户体系,每个 App 以 mobile 用户运行

# 3.3 内存管理与VM

iOS 的虚拟内存系统建立在 Mach VM 之上。每个 App 进程拥有独立的 64 位虚拟地址空间(虽然物理内存只有 2-6 GB)。

关键机制:Mach 不是给 App "一段物理内存",而是给一段 VM Object,物理页在真正访问时(缺页中断)才分配。

App 调用 malloc(100 MB)
        │
        ▼
libmalloc → mmap(MAP_ANON, 100MB)     ← 只分配虚拟地址,物理内存为 0
        │
        ▼ (App 第一次写这 100 MB)
Mach 缺页中断 → 分配物理页             ← 此时才真正消耗物理内存

这也是为什么 UIImage(named:) 加载一张 20 MB 的图片,解码后可能占 40 MB 物理内存——解码后的位图是真正被"写"过的内存,触发了物理分配。而压缩的 PNG 数据在文件系统上只占一份。

Jetsam 机制:当系统物理内存不够时,Jetsam(iOS 的 "OOM Killer")会按优先级杀进程。前台 App 几乎不会被杀,后台 App 最先被清除。这就是为什么后台的 App 经常会"重启"——不是 bug,是被 Jetsam 杀了。

# 4. dyld与Mach-O加载

# 4.1 Mach-O文件结构

iOS 的可执行文件和动态库都是 Mach-O(Mach Object)格式——这是 XNU 内核原生支持的二进制格式,与 Linux 的 ELF、Windows 的 PE 是同类概念。

一个 Mach-O 文件由三部分组成:

┌─────────────────────┐
│     Header          │  ← CPU 类型(arm64)、文件类型(可执行/动态库)、加载指令数
├─────────────────────┤
│  Load Commands      │  ← 每一条告诉 dyld "做什么":
│  - LC_SEGMENT_64    │     把 __TEXT 段映射到 VA 0x100000000,r-x 权限
│  - LC_SEGMENT_64    │     把 __DATA 段映射到 VA 0x100008000,rw- 权限
│  - LC_LOAD_DYLIB    │     依赖 UIKit,去找它的路径
│  - LC_MAIN          │     入口点偏移(代替旧的 LC_UNIXTHREAD)
│  - LC_CODE_SIGNATURE│     代码签名信息
├─────────────────────┤
│     Data            │  ← __TEXT(代码)、__DATA(全局变量)、__LINKEDIT(符号表)
│  ┌─── __TEXT ────┐  │
│  │ __text (代码) │  │     可执行文件 = 一个 Header + N 个 Load Command + 数据
│  │ __stubs       │  │     动态库同理,区别是 type 字段不同
│  │ __cstring     │  │
│  ├─── __DATA ────┤  │
│  │ __data        │  │
│  │ __bss         │  │
│  │ __objc_class  │  │     ← ObjC 的类列表、方法列表全在这
│  ├─── __LINKEDIT ─┤  │
│  │ 符号表         │  │
│  │ 字符串表       │  │
│  │ 重定位信息     │  │
│  └───────────────┘  │
└─────────────────────┘

查看 Mach-O 的命令:

xcrun size -l -m App           # 查看 __TEXT/__DATA 大小
xcrun otool -l App | grep LC_  # 列出所有 Load Command
xcrun dyldinfo -exports App    # 查看导出符号

# 4.2 dyld加载流程

dyld(dynamic link editor)是 iOS 的动态链接器,相当于 Linux 的 ld-linux.so。当一个 App 进程被创建后,内核直接把 dyld 的路径写进进程,dyld 成为进程的第一段代码——它比 main() 先运行。

dyld2 加载流程(iOS 12 之前):

内核 execve() → 加载 dyld 到进程空间
                    │
    ┌───────────────┼───────────────┐
    ▼               ▼               ▼
1. 加载所有      2. 符号绑定      3. 初始化
   动态库         (rebase/bind)    (initializer)
   ──────        ─────────────    ─────────────
   解析每个      修复内部指针     执行 +load 方法
   Mach-O 文件   指向正确 VA      调用静态初始化
   映射到内存    绑定外部符号     创建 ObjC 类
                                 调用 __attribute__((constructor))
                                       │
                                       ▼
                                  main() 开始执行

dyld3 的优化(iOS 12+):dyld3 引入了启动闭包——在 App 安装或系统更新时,提前把"这 37 个库怎么加载、符号怎么绑"全部算好,存成缓存。冷启动时直接读闭包,省去解析和符号查找。这是 iOS 12 冷启动提速 30%+ 的核心原因。

# 4.3 动态库与共享缓存

你能在 /usr/lib/ 下找到 UIKit、Foundation、libobjc 等动态库——但它们并不是以独立 .dylib 文件形式存在的。iOS 把所有系统动态库合并成一个巨大的共享缓存(dyld shared cache,位于 /System/Library/Caches/com.apple.dyld/),通常 1-2 GB:

所有 App 进程共享同一个 dyld cache 的只读部分:
   App A ─┐
   App B ─┼─► 同一份 UIKit __TEXT 的物理页
   App C ─┘

这就是为什么:
- iOS 启动比 Android 快(不用每次解析 dex/oat)
- 所有 App 的 UIKit 在物理内存里只占一份
- 即使是 2 GB 内存的设备,跑 50 个 App 也不会 OOM

# 5. SpringBoard与应用生命周期

# 5.1 SpringBoard的角色

SpringBoard 是 iOS 的桌面进程,相当于 macOS 的 Finder + Dock。它负责:

  • 显示主屏幕和 App 图标
  • 响应用户点击图标 → 启动对应 App
  • 管理 App 切换器(多任务卡片)
  • 处理锁屏、通知中心、控制中心

从点击图标到 main() 的完整链路:

用户点图标
    │
    ▼
SpringBoard 收到 touch 事件
    │
    ├─ 创建新进程 (fork + exec) ────────────────── 内核
    │    ├─ 分配虚拟地址空间
    │    ├─ 加载 dyld → dyld 加载 App 及依赖库
    │    ├─ 执行 +load → ObjC Runtime 初始化
    │    └─ 调用 main()
    │
    ├─ 同时播放启动动画(缩放图标到全屏)
    │
    ▼
App 的 main() → UIApplicationMain() → AppDelegate

SpringBoard 给 App 的启动时间限制:iOS 大约 20 秒内必须完成启动并渲染第一帧,否则会被系统 watchdog 杀掉(0x8badf00d 错误码)。

# 5.2 App五种状态切换

      Not Running ──────── 被杀 / 手动杀死 ────────┐
           │                                         │
      SpringBoard 点图标                              │
           │                                         │
           ▼                                         │
       Inactive ── 短暂过渡(启动动画期间)            │
           │                                         │
           ▼                                         │
        Active ── 前台活跃(用户正在用)               │
           │                                         │
      按 Home / 切 App                                │
           │                                         │
           ▼                                         │
       Inactive ── 短暂过渡                           │
           │                                         │
           ▼                                         │
     Background ── 后台运行(限时 30s~3min)           │
           │                                         │
      任务完成 / 超时                                  │
           │                                         │
           ▼                                         │
      Suspended ── 挂起(不执行代码,内存保留)────────┘

关键细节:Suspended 状态的 App 内存还在,但不执行任何代码。当系统内存不够时,Jetsam 首先清除 Suspended 状态的 App。用户重新打开时从 Suspended 恢复快,从 Not Running 冷启动慢——这就是"后台被杀掉"和"真正的关闭"的区别。

# 5.3 后台执行机制

iOS 对后台的限制极其严格——这是 iOS "省电"和"流畅"的根基。一个 App 进入后台后通常只有约 30 秒的时间完成善后工作。

后台执行的几种合法方式:

机制 时长 适用场景
beginBackgroundTask 30s~3min(iOS 13+ 约 30s) 保存数据、关闭连接
VoIP Push 长驻 语音/视频通话类 App
Background Fetch 定时唤醒几秒 刷新内容、预加载
Remote Notification 推送触发,30s 收到消息后更新数据
BGTaskScheduler 系统择机调度 定期清理缓存

面试常考题:"App 进入后台后能活多久?" 答:最长 3 分钟(beginBackgroundTask 申请),过期后系统强制挂起。只有 VoIP、定位、音频播放这三类有特权长驻后台。

# 6. 沙盒与安全模型

# 6.1 沙盒的三层隔离

iOS 的沙盒是强制访问控制(MAC) 机制的实现,每个 App 被关在自己的"盒子"里。三层隔离:

第一层:文件系统隔离
  ┌─────────────────────────────┐
  │ /var/mobile/Containers/     │
  │   Data/{UUID}/              │  ← 每个 App 的数据容器
  │     Documents/              │     (iTunes 备份)
  │     Library/Caches/         │     (可清理)
  │     Library/Preferences/    │     (NSUserDefaults 存在这)
  │     tmp/                    │     (随时可能清空)
  │                             │
  │ /var/containers/Bundle/     │
  │   {UUID}/YouApp.app/        │  ← App Bundle(只读)
  └─────────────────────────────┘

第二层:进程隔离
  每个 App 以独立的 mobile 用户身份运行
  App A 无法读取 App B 的内存(Mach VM 隔离)
  跨进程通信必须通过系统提供的 XPC / URL Scheme

第三层:权限管控(Entitlements)
  网络访问?→ com.apple.security.network.client
  相机?    → com.apple.security.device.camera
  后台模式?→ com.apple.developer.background-modes
  没有相应的 entitlement,即使代码写了 API 调用也会被内核拒绝

# 6.2 签名与权限控制

iOS App 必须经过 Apple 代码签名才能运行。签名链分为三层:

开发者证书 (Apple 签发)
      │
      ▼
Provisioning Profile (描述文件)
   ├─ 允许的设备 UDID 列表
   ├─ Entitlements 白名单
   └─ 关联的 App ID
      │
      ▼
App 可执行文件签名 (Code Directory)
   └─ 每页代码的哈希值 → 运行时校验是否被篡改

每次 App 启动,内核会验证代码签名。验证通过后开启沙盒限制。企业证书签名的 App 为什么能"侧载"?因为企业证书跳过了 App Store 审核,但签名链仍然存在,权限受到 Profile 中 entitlements 的白名单控制。

# 7. 案例回溯与设计哲学

# 7.1 案例真相揭晓

回到第 1 章的冷启动问题,七个疑问现在逐条作答:

疑问 答案
① iOS 系统分几层?App 跑在哪? 第 2 章:五层架构,App 跑在 Cocoa Touch 层之上
② Mach-O 为什么不是 ELF? 第 4.1:Mach-O 是 XNU 原生格式,dyld 解析它的 Load Command 做映射
③ dyld 怎么加载动态库? 第 4.2-4.3:dyld 依次 mmap 每个 Mach-O,处理 rebase/bind,执行初始化;共享缓存加速了系统库加载
④ 点图标到 main() 发生什么? 第 5.1:SpringBoard→fork→dyld→main,整个链在 400ms 以内(否则影响启动体验)
⑤ 沙盒怎么隔离 App? 第 6 章:文件系统+进程+entitlements 三层隔离
⑥ Mach 和 BSD 分别管什么? 第 3 章:Mach 管进程/内存/IPC,BSD 管文件/网络/权限
⑦ 后台为什么杀得狠? 第 5.3:iOS 用"冻结后台→杀 Suspended→Jetsam"三级机制省电,后台特权极为有限

三种优化方案(按收益排序):

方案 A:减少 +load 耗时(最直接)

// ❌ 在 +load 里做初始化
+ (void)load {
    [self setupSDK]; // dyld 启动阶段串行执行
}

// ✅ 推迟到 +initialize 或首次调用
+ (void)initialize {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ [self setupSDK]; });
}

方案 B:合并动态库 / 改用静态库

将 37 个动态库中无共享必要的改为静态库,减少 dyld 的 rebase/bind 开销。但注意静态库会增大包体积。

方案 C:使用 DYLD_PRINT_STATISTICS 诊断

// Xcode Scheme → Environment Variables
DYLD_PRINT_STATISTICS = 1
DYLD_PRINT_STATISTICS_DETAILS = 1

下次启动时控制台输出详细耗时表,每个 dylib 的加载时间一目了然。

# 7.2 设计哲学回扣

整理本篇的三条跨篇适用的设计哲学:

哲学 1:分层抽象——App 不需要知道自己跑在什么芯片上

Cocoa Touch 向上屏蔽了所有硬件差异。同样一句 UIView.animate,iPhone 13 的 A15 和 iPhone SE 的 A9 都能跑——硬件差异被 Core Animation → Metal/OpenGL ES → GPU Driver 三层消化了。分层让 App 开发者只关心"做什么",不关心"怎么做"。

哲学 2:以空间换时间——dyld shared cache 的秘密

iOS 把 UIKit 等系统库的代码段合并成一个 1-2 GB 的大文件,映射进每个进程。代价是磁盘空间,收益是所有 App 共享同一份物理页 + 启动时直接 mmap 无需解析。这是 iOS 比 Android 启动快的关键设计。

哲学 3:fail fast——watchdog 与 Jetsam 的共同信仰

iOS 不允许一个 App 拖慢整个系统。启动超 20s → watchdog 杀;后台超时 → suspend;内存不够 → Jetsam 杀。表面"残酷",实际是保护用户体验——宁可杀你一个 App,不让整个手机卡。这与 Unix "fail fast" 哲学一脉相承。


下一篇:你已经知道 App 是怎么启动的,下一章进入 02.Runtime消息转发机制 (opens new window)——把 ObjC 最核心的 "消息传递三件事" 剖到源码级别。

上次更新: 2026/06/28, 17:55:19
Switf入门到精通下
Runtime消息转发机制

← Switf入门到精通下 Runtime消息转发机制→

最近更新
01
科学方法实践论法
06-28
02
辩证思维矛盾论法
06-28
03
毛选中的调查观念
06-28
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 鄂ICP备2024073355号-1 | 鄂ICP备2024073355号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式