編輯推薦
√從基本原理出發,了解蘋果設備性能的常見陷阱和誤解,解決蘋果系統性能問題;
√理解最最佳化原則、測量、工具、陷阱和技巧;
√了解什麼時候要仔細最佳化,什麼時候不值得花時間最佳化;
√平衡性能和封裝,創建高效的對象表示、通信、數據訪問和計算;
√避免拖慢Objective-C程式和阻礙後續最佳化的錯誤;
√修復記憶體和資源管理中的漏洞和其他問題;
√解決與驅動器、網路、序列化和SQLite相關的I/O問題;
√了解代碼繪圖和不會對有限的iOS設備資源造成太大負擔的用戶界面;
√所有開發人員都需要了解的關於Swift的性能信息。
內容提要
隨著套用功能的日益增加,性能問題也逐漸浮出水面,進入我們的視野之中。《iOS和macOS性能最佳化:Cocoa、Cocoa Touch、Objective-C和Swift》作者Marcel Weiher在性能調優領域有著豐富的經驗,在他的帶領下,你將會了解如何提升CPU、記憶體、I/O、圖像、Swift等方面的性能,如何在開發過程中定位到性能的瓶頸和問題,他同時還介紹了性能最佳化的編程技巧和最佳實踐,從而幫助你寫出更高效、更快速的代碼。此外,你還將學習到定位性能問題的工具使用方法以及最佳實踐,並跟隨示例來學習性能最佳化。
《iOS和macOS性能最佳化:Cocoa、Cocoa Touch、Objective-C和Swift》適合尋求進階及所有對性能最佳化感興趣的iOS 開發人員閱讀。
目錄
1 CPU:原理 1
一個簡單的例子 2
(微)基準的危險 3
更多整數求和的方式 4
Swift 5
其他語言 7
混編的力量 9
趨勢 10
操作成本 12
複雜度計算 14
總結 16
2 CPU:測量和工具 17
命令行工具 18
top 18
time 19
sample 19
Xcode 測量工具 22
Instruments 23
設定和數據收集 24
性能分析選項 25
基本分析 27
原始碼 29
數據挖掘I:Focus 31
數據挖掘II:Pruning 34
內部測量 35
測試 36
dtrace(dynamic tracing,動態跟蹤) 37
職責之外的最佳化 38
總結 39
3 CPU:陷阱和最佳化技巧 41
數據表示 41
基本類型 42
字元串 45
對象 47
存取器 48
公共訪問(Public Access) 51
對象創建和快取 52
可變性和快取 53
惰性求值 55
快取注意事項 55
陷阱:通用(中級)表示 57
數組和批處理 58
字典 60
訊息傳遞 63
IMP 快取 65
轉發 67
均勻性和最佳化 69
方法 70
陷阱:CoreFoundation 70
多核 71
執行緒(Thread) 72
工作佇列 73
有節制地最佳化 74
4 CPU 實戰:XML 解析 77
HTML 掃描器 78
將回調映射為訊息 81
對象 83
對象的高效性能 85
性能評估 88
調整 91
最佳化整個組件:MAX 92
MAX 實現 94
總結 95
5 記憶體:原理 97
記憶體層次結構 97
Mach 虛擬記憶體 103
堆和棧 104
棧分配 106
使用malloc()進行堆分配 108
資源管理 111
垃圾回收 111
Foundation 對象所有權 112
跟蹤垃圾回收 113
自動引用計數(Automatic Reference Counting) 114
過程式資源回收 115
總結 115
6 記憶體:測量與工具 117
Xcode 計量表 117
命令行工具 118
top 118
heap 120
leaks 及malloc_debug 122
代碼內進行記憶體測量 123
記憶體監測工具 124
Leaks 124
Allocations 125
VM Tracker 132
計數器與性能監測事件 133
總結 134
7 記憶體:陷阱和最佳化技巧 137
引用計數 137
避免記憶體泄漏 139
Foundation 對象和基本類型對比 141
更小的結構 143
千禧危機 145
壓縮 145
可清除記憶體 146
記憶體與並發 146
架構注意事項 147
臨時分配與對象快取 152
NSCache 與libcache 153
記憶體映射檔案 154
madvise 157
iOS 注意事項 158
ARC 最佳化 158
總結 161
8 記憶體管理實戰:FilterStream 架構 163
UNIX 管道及過濾器 163
面向對象的過濾器 165
DescriptionStream 166
消除description 中的無限遞歸 170
數據流層次結構 172
總結 173
9 Swift 175
Apple 所聲稱的Swift 性能 175
語言特性 177
基準代碼 179
Swift 性能評估 180
基本性能特徵 180
集合 181
更進一步 190
Nginx HTTP 解析器 190
Freddy JSON 解析器 191
圖片處理 191
觀察 192
編譯時間 193
類型推斷 193
泛型特化 195
全模組最佳化 197
控制編譯時間 197
面向最佳化器編程 198
一個足夠智慧型的編譯器 199
最佳化編譯器之死 201
實用建議 203
備用方案 204
總結 207
10 I/O:原理 209
硬體 209
硬碟驅動器 209
固態硬碟 211
網路 212
作業系統 212
抽象概念:位元組流 212
檔案I/O 214
網路棧 218
總結 218
11 I/O:測量與工具 221
負形空間:top 與time 222
信息概覽:iostat 和netstat 223
Instruments 224
詳細追蹤:fs_usage 228
總結 231
12 I/O:陷阱和最佳化技巧 233
將位元組封裝為NSData 233
記憶體映射異常 235
如何分塊 237
UNIXy I/O 238
網路I/O 240
堆疊傳輸 241
限制請求 243
數據處理 244
異步I/O 245
HTTP 服務 246
序列化 250
記憶體轉儲 251
一個簡單的XML 格式 252
屬性列表 254
歸檔 256
序列化總結 258
CoreData 260
批量創建和更新 261
Fetch 和Fault 技術 263
對象互動 266
子集 266
分析 267
SQLite 267
關係型和其他非資料庫 269
事件發布 270
混合形式 271
隔離存儲 272
總結 272
13 I/O:實戰 273
iPhone 遊戲字典 273
有趣的屬性列表 277
二進制屬性列表讀取器 278
懶載入 282
避免中間代碼 284
逗號分隔值 287
公共運輸調度數據 289
站點信息 290
站點停靠時間檢索 291
站點停靠時間導入 292
更快的CSV 解析 294
對象分配 294
Push 與Pull 的比較 296
感興趣的鍵 296
並行 296
總結 299
14 圖像和UI:原理 301
回響能力 301
軟體和API 302
Quartz 和PostScript 圖像模型 305
OpenGL 307
Metal 307
圖形硬體加速 307
從Quartz 到Core Animation 311
總結 314
15 圖像和UI:測量和工具 315
CPU 分析儀 315
Quartz 調試 317
Core Animation 工具 318
當CPU 不再是問題 319
我在測量什麼 327
總結 329
16 圖像和UI:陷阱和最佳化技巧 331
陷阱 331
最佳化技巧 332
過多通信導致安裝緩慢 333
節流顯示 333
使用節流顯示 335
今日安裝程式和進度報告 335
iPhone 無法承受之重 336
一切都是假象 338
圖像的縮放和剪下 338
縮略圖繪製 340
如何確定沒有繪製縮略圖 341
如何真的不繪製縮略圖 341
如何繪製非縮略圖 342
在iPhone 上繪製直線 344
總結 346
17 圖像和UI:實戰 347
優美的天氣套用 347
更新 348
探索PNG 348
頭腦風暴 350
JPEG 數據點 350
測量時的小錯誤 351
JPNG 與JPJP 353
優美的啟動 353
Wunderlist 3 354
Wunderlist 2 354
整體架構 355
URI 與進程中REST 356
最終一致的異步數據存儲 357
RESTOperation 佇列 358
流暢、反應靈敏的UI 359
簡評Wunderlist 361
總結 361
作者簡介
Marcel Weiher 是一名軟體工程師和研究人員,擁有超過25 年的Cocoa 相關技術經驗。Marcel 致力於性能最佳化相關的工作,曾在英國廣播公司最佳化過世界上極繁忙的網路的性能,解決了當下機器上難以忍受的積壓問題,而其在Apple 的Mac OS X 性能團隊任職時,也幫助過其他工程師提高代碼性能。
除了幫助知名公司和初創企業開發屢獲殊榮的軟體以及組建開發團隊,Marcel 還教授課程,維護部落格,出席會議演講,為開源項目做貢獻,並發明了如高階訊息傳遞等新技術。自1987 年開始,Marcel 著手Objective-C 的實現,開始從事與程式語言相關的工作,最終實現了Objective-Smalltalk 架構研究語言。Marcel 目前在柏林的微軟公司擔任首席軟體工程師,並擁有自己的軟體和諮詢公司metaobject ltd。
譯者序
我們在開發套用的時候,最關心的都是些什麼呢?首要的自然就是功能需求了,此外還有那些炫酷的用戶界面和轉場動畫。當我們進入書店,或者在網上搜尋時,映入眼帘的普遍都是開發入門、功能需求、動畫特效等諸如此類的書籍和文章。那么,我們何時才會關注那些所謂的“非功能性需求”呢?
在我們翻譯的上一本書《iOS 套用安全權威指南》中,我們很高興地看到了iOS 開發中關於“安全性”需求的話題。在本書中,我們將繼續關注“性能和可靠性”這一非功能性需求。
提到性能,我們通常想到的是後台的伺服器性能和網路頻寬。在出現性能問題的時候,我們會想方設法地提升後台伺服器的性能,增加CPU 核心、增加記憶體、增加網路頻寬……但是有沒有想過,有時候套用本身的性能也會阻礙用戶數量的增長,甚至嚴重影響用戶體驗。試想,如果用戶在使用套用的時候,出現了嚴重的卡頓,這種情況對於用戶而言往往是無法忍受的。這對很多公司而言,致命性不言而喻。更嚴重的是,套用一旦出現了性能問題,我們是沒辦法通過增加CPU 核心、記憶體等方法來進行提升的。因此,我們需要對套用進行性能調優。
但是,目前市面上關於iOS 性能最佳化的文章和書籍實在是少之又少,我們通常會看到人們用Instruments 的Allocations、Leaks 等工具來檢查性能問題,但是它們的具體用法是怎么樣的呢?我們要怎樣做才能找到套用真實的性能瓶頸呢?有哪些問題是通過編寫代碼本身就可以規避的呢?這些,本書都能夠告訴你。
我們相信,每位軟體開發者都有一種精益求精、追求卓越的心態和想法,在我們完成了龐雜的功能需求之後,自然就會開始關注如何提升用戶體驗,其中就包括性能最佳化。
無論你的套用規模如何,我們都強烈建議大家閱讀本書,掌握一些基本的技巧,只要在開發過程中規避這些陷阱和漏洞,那么基本上我們的套用就能夠滿足性能的要求,在絕多數時間,使你完全沒必要擔憂性能的相關問題。
我們都知道,Xcode 擁有一個簡單的性能檢測視窗Debug Navigator,其中分別展示了CPU、記憶體、硬碟、網路的使用量等。類似地,本書包含如下四部分內容:CPU、記憶體、I/O,以及圖像處理和回響速度。每部分內容都同時包括了基本的理論知識、測量的工具和度量標準、常見的問題和處理方法,以及真實的案例演示。內容循序漸進,由淺至深,無論你是急於尋找性能問題的解決方案,還是想要系統化地學習性能調優的相關知識,都能夠依據這個完整的架構體系尋找到想要的內容。
在本書翻譯過程中,由於書中的內容對於我們而言也比較新穎,在百忙之餘,我們也一一根據書中的案例和步驟先行學習、試驗和體會,以期能夠用更為準確的語言和文字,將書中的思想完整地分享給各位讀者朋友。在此也特別感謝參與校對的SwiftGG 翻譯組的小夥伴們,對我們在翻譯過程中出現的錯誤進行了勘正。同時也感謝電子工業出版社的編輯、審稿專家,他們認真負責、高效細心地進行了編輯和校對,也給我們提出了不少好的建議。當然,由於本書用到了大量的專業術語,在中文世界中找不到相應的描述,因此我們也斗膽“創造”了很多新詞,如果出現了缺漏、不準確、不到位的情況,還請各位讀者批評指正。
最後,再次感謝你關注這本講解性能最佳化的書籍,我們相信你一定能從這本書中學習到各種有用的知識,向進階的iOS 開發者更進一步!
李俊陽
2018 年3 月3 日
前言
性能是軟體極其重要的特性之一。若沒有世界一流的性能,軟體也就稱不上是世界級的。長期以來,硬體的改善意味著擔心軟體的性能似乎是浪費時間的,但隨著摩爾定律不再自然而然地提供顯著的自動性能改進,性能最佳化也逐步回到了計算機科學和工程的前沿。
此外,儘管底層硬體的性能已經提升了很多倍,但終端用戶對性能提升的感知似乎並不明顯。比爾·蓋茨認為“軟體的速度每18 個月就會變慢一半”,同樣在A Plea for LeanSoftware(《為軟體瘦身請命》)一文中提出的維爾特定律還認為,“軟體變慢的速度永遠快過硬體變快的速度”1。
iPad 面世之初,行業資深人士被其流體式的布局界面所驚艷,但同時不得不接受一個只配備了1GHz 的CPU,這是讓人感到遺憾的一點。不過,那時的iPad 比我的Apple II快了1000 多倍,比大屏的NeXT Cube 也要快40 倍。如果真的有什麼值得詫異的,那就是在使用GPU 處理螢幕渲染的時候,它居然沒怎么變快。
本書將嘗試在Objective-C、Cocoa 和Cocoa Touch 的背景下深入了解這些發展的根本原因,並嘗試提供技術,幫助我們充分利用計算機驚人的原始力量——那些易於肆意揮霍的力量。我會試圖告知何時揮霍計算機的性能是恰當的,以及何時需要對性能引起高度重視。程式設計師的注意力也是一種稀缺資源,但卻經常浪費在嘗試最佳化無關緊要的部分程式上。
主題將涵蓋延遲與頻寬,處理事項成本損耗(開銷)與實際完成工作的對比,其具有普遍性,且硬體和軟體棧的表現形式隨級別不同而不同。
你可能注意到任何單一的操作時間取決於機器的速度,而機器總是足夠快的,因此得出關鍵方程項目數損耗。大多數最佳化是減少公式的一部分或兩部分,通常我們要先嘗試將其分解。
降低成本損耗的一種常用方法:認識到損耗實際上是由損耗1 和損耗2 兩個獨立的成本組成的,並且兩者之中有且僅有一個需要套用於所有項目——項目數×(損耗1+損耗2)→損耗1+項目數×損耗2。我稱之為基本最佳化方程,大部分最佳化技術均屬於這一類,它也是構成我們每天處理的大多數硬體/軟體棧的基礎。
本書有一個非常規則的目錄結構,將依次討論性能的4 個基本主題領域:
1.CPU 的性能
2.記憶體
3.I/O
4.圖像和回響速度
儘管已經努力保證每個主題領域的獨立性,但是邏輯之間千絲萬縷,因此對基礎的主題有一定了解有助於對後續主題的理解。
上述4 個主題分別又被劃分成4 個特定的興趣領域,如下。
1.原理。
2.測量和工具。
3.陷阱和最佳化技巧。
4.實戰演示套用技術。
再次強調,我們將遵循這樣一個邏輯結構:在進行實際的性能最佳化技術之前,你需要了解一些理論知識並知道如何測量,同樣地,如果基本熟悉前面幾個話題,應該也能夠深入感興趣的特定領域。
本書採用這種結構劃分成了44 =16 章,加上記憶體和I/O 之間穿插的特別章節Swift,總計17 章。Swift 在整本書中被廣泛使用,其獨特的性能特點值得我們新開一章來討論。
對我而言,軟體性能是一種激情和呼喚,貫穿了我的整個職業生涯。關於性能,我深有體會,性能無法自動最佳化,我們也無法在最後時刻棄它而去。另一方面,不要過分擔心性能,才能集中精力在真正需要的性能工作上。這並非自相矛盾,設定一個合理的基礎性能水平,通常情況下軟體都是能夠達到的,這樣就免去了大部分時間都在對性能擔憂的困擾。
簡而言之,本書是關於如何出色完美地提升軟體執行效率的一本書。