WWDC - iOS記憶體效能及原理 筆記
iOS記憶體的基本原理記憶體是如何初始化和被管理的?
在iOS內,指標的位址範圍很大, 32位CPU上有 4GB 大小, 64位CPU上有 18EB 大小 (大約有2的60次方), 這麼大的指標位址範圍會致使我們看來系統記憶體有這麼大,實際上實體記憶體可能沒有這麼大,這個大小被稱為虛擬記憶體, 在OS X 中系統使用硬碟來儲存記憶體中不經常使用的資料來作為記憶體的備份存放區, 在記憶體中存有硬碟資料的指標地址, 需要的事後才寫入記憶體.
然而, 在iOS中沒有備份存放區, iOS中唯讀類型的資料已經存在硬碟上, 在需要時寫入記憶體使用量, 可讀寫資料是常駐記憶體的,不會移除, 一旦可使用記憶體達到臨界值, 系統會發出記憶體不夠用的警告,由應用程式主動釋放資源,若釋放失敗或沒有排除警告,會直接被系統終結程式.
虛擬記憶體
iOS的實體記憶體被分割成大小為 4KB 的頁, 而且不是所有的頁都能被應用訪問到. 虛擬記憶體是在kernel和應用程式層之間的一層,由於當我們每次需要記憶體的時候都直接調用kernel去申請記憶體的過程的代價是很大的, 所以底層會直接與虛擬記憶體申請空間, 虛擬記憶體會與kernel通訊, 建立 VM Object來匹配實體記憶體,:
在記憶體的堆中, 我們應用的資料只佔一部分, 其他還有framework建立的對象和緩衝, 記憶體中還有一些靜態常量, 線程的堆棧, 圖片資料, CALayer的緩衝, 資料庫的緩衝
記憶體類型: 乾淨記憶體和髒記憶體
乾淨記憶體: 從磁碟上拷貝到記憶體中的空間, 比如, 代碼, framework,記憶體對應檔.
髒記憶體: 其他的記憶體空間. 比如 在堆上的初始化資料, 資料庫緩衝,解壓的圖片資料等.
大部分應用初始化的資料都是髒記憶體
舉例如下:
- (void)displayWelcomeMessage {NSString *welcomeMessage = [NSString stringWithUTF8String:“Welcome to WWDC!”];self.alertView.title = welcomeMessage;[self.alertView show];}
welcomeMessage 是髒記憶體, 因為字串Welcome to WWDC!
在待用資料區,它倍複製一份到堆上給了welcomeMessage.
- (void)displayWelcomeMessage {NSString *welcomeMessage = @”Welcome to WWDC!”;self.alertView.title = welcomeMessage;[self.alertView show];}
這次welcomeMessage是乾淨記憶體, 因為沒有複製一份.
- (void)allocateSomeMemory {void *buf = malloc(10 * 1024 * 1024);…}
雖然malloc是在堆上初始化資料, 但是 buf 沒有實際儲存資料, 所有buf是乾淨記憶體.
- (void)allocateSomeMemory {void *buf = malloc(10 * 1024 * 1024);for (unsigned int i = 0; i < sizeof(buf), i++) { buf[i] = (char)random();}…}
但是一旦使用了buf後, buf就是髒記憶體了.
UIImage *wwdcLogo = [UIImage imageNamed:@”WWDC12Logo”];
初始化UIImage,UIImage其實是CGImage的封裝, CGImage產生jpeg 和 bitmap, 在記憶體中會有未壓縮的bitmap資料,是髒記憶體.
當iOS運行在低記憶體是會發生什麼
iOS開始的時候, 乾淨記憶體比例很大,當我們運行app的時候, 隨著啟動並執行進行, 初始化資料, 產生了髒記憶體, 進而是髒記憶體比例增大,乾淨記憶體比例減小, 最後產生記憶體壓力, 記憶體不夠用了, 這時候系統會終結掉後台應用, 釋放屬於應用的髒資料, 騰出記憶體空間.
記憶體警告這是一次挑戰會發生在記憶體有限的裝置上 是最後保護使用者體驗的機會 保證你的應用能響應記憶體警告,警告通知是在主線程上觸發,避免重複的初始化大資料這是一次機會儘可能的釋放記憶體,但是不要影響使用者體驗 記憶體警告傳遞到應用程式有幾種方式:
通知
UIApplicationDidReceiveMemoryWarningNotification UIApplication代理方法
-[id -applicationDidReceiveMemoryWarning:]
UIViewController方法
-[UIViewController didReceiveMemoryWarning]
一定要注意髒記憶體,因為髒記憶體是由應用建立,如果不清除,只有應用被終結後才能釋放, 使用Profile的VM Tracker去檢測記憶體使用量情況, 避免出現大範圍經常性波動, 減少記憶體還可以使用 @autoreleasepool
.
找到記憶體的問題減少記憶體的使用: 清楚我們應用的視圖層級,只建立必要的視圖. 避免迴圈的導致堆增長,不要忽略那些小的對象. 避免記憶體增長:
不可訪問的,沒有任何指標指向 不能被再次使用 被拋棄的記憶體
仍然有指標引用它, 但是被浪費的 從未被使用過 緩衝
被引用了和等待使用 可能永遠不會被使用了
如何檢測記憶體問題
記憶體不應該在重複一個操作中持續增長, 比如: push和pop UIViewcontroller,滑動UITableview, 操作資料庫搜尋
使用工具和陷阱
使用 Allocations Instrument 來檢測記憶體是否泄露, 遇到記憶體泄露可以檢查是否在塊中使用了self對象, 應該換成 __weak 修飾的self這樣不增加計數引用.
更多的資訊可以查閱官方手冊.
Instruments Documentation
Instruments User Guide
Instruments User Reference
地址
官方關於虛擬記憶體的說明