在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開始的時候, 干淨內存比例很大,當我們運行app的時候, 隨著運行的進行, 初始化數據, 產生了髒內存, 進而是髒內存比例增大,干淨內存比例減小, 最後產生內存壓力, 內存不夠用了, 這時候系統會終結掉後台應用, 釋放屬於應用的髒數據, 騰出內存空間.
-[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
地址
官方關於虛擬內存的說明