標籤:line 檔案的 org 優先 實體記憶體 優先順序 需要 wiki bsp
http://www.cocoachina.com/ios/20170216/18689.html
iOS 記憶體機制特點
iPhone 裝置的 RAM 一直非常緊缺,iPhone 一代只有 128MB,直到 iPhone5 時達到了 1GB,並且在 iPhone7 plus 達到了 3GB。StackOverFlow 上提供了部分 iPhone 機型的可用記憶體數目。
在可用實體記憶體較少時,iOS 會給各應用發出低記憶體廣播通知,如果此後可用記憶體仍然低於特定值,則會殺死優先順序較低的進程。
案頭作業系統可以在實體記憶體緊張的時候把暫時不用的實體記憶體置換到磁碟上,並在需要的時候再次載入到記憶體中。而 iOS 沒有這種機制,原因是行動裝置的快閃記憶體沒有 PC 機那麼大的硬碟,而且頻繁的讀寫快閃記憶體會降低其壽命。目前 iOS 在記憶體不足時採用的方案是殺死優先順序較低的進程。
和大多數案頭作業系統一樣,iOS 也使用虛擬記憶體機制。
虛擬記憶體
關於虛擬記憶體的原理和優缺點就不再累述,這裡說下 iOS 虛擬記憶體機制中與眾不同的地方。
記憶體分頁
iOS 把虛擬記憶體每 4KB 劃分成一個 Page,並不是所有的 Page 都會映射到實體記憶體中。每個 Page 有三種狀態:
是否 Resident 是一個 Page 狀態的重要標識,如果 Page 被映射到記憶體裡了,這個 Page 就是 Resident 狀態,否則就是 Nonresident 狀態;
基於 readonly 檔案而被載入到記憶體中的 Page 稱為 clean memory,比如:系統 framework、可執行檔、通過 mmap 方式讀取的檔案 等。這種 Page 由於是載入自不可變的檔案,因此可以在實體記憶體緊張時被 iOS 自動 unload 出去,並且在需要的時候再重新從原來的檔案載入到記憶體中。
凡是非 clean 的 Page 都是 dirty 的,它們的共同特點是 Page 在快閃記憶體中沒有對應的檔案,比如通過 alloc 在堆上建立的記憶體空間,已經解壓的圖片,database caches 等。dirty memory 不能被作業系統交換出去,只有在進程被殺死的時候才能被回收,因此在系統發生記憶體警示時,如果進程建立了大量的 dirty memory,那麼將很有可能被 kill 掉。
舉例說明
如前問所述,Malloc 的記憶體都是 Resident dirty 的,但事實上並非如此,比如:
| 1 |
char *p = valloc(2 * 4096); |
此時會在虛擬記憶體裡申請兩份 4096 位元組的記憶體,但由於申請後沒有使用,作業系統不會真正為剛申請的記憶體空間分配對應的實體記憶體空間,因此此時該記憶體空間處於 Nonresident 狀態。如果對 p[0] 賦值:
此時 P[0] 會被載入到實體記憶體上,由此變成 Resident dirty 狀態,同理如果對 p[1] 賦值也一樣。
一個檔案通過如果下述 mmap 方式載入:
| 1 |
NSData *data = [NSData dataWithContentsOfMappedFile:file];char *p = (char *)[data bytes]; |
此時檔案由於未被使用,因此也僅僅是在虛擬記憶體中,作業系統並沒有將其映射到物理裡,因此所屬 Page 的狀態是 Nonresident。如果調用以下代碼:
此時由於該檔案的 p[0] 部分被使用,作業系統就會將 p[0] 部分載入到實體記憶體中,又因為 p 對應的儲存地區是一個 mmap 方式載入的唯讀檔案,因此 p[0] 對應的 Page 就是 Resident clean 的,而 p[1] 往後的部分由於仍然未被使用,Page 的狀態不變。
需要做什麼
對於開發人員來說,要想減少應用因記憶體警示被系統殺掉,應做到以下幾點:
參考文檔
List of iOS devices
WWDC2010 Session 417:Advanced Performance Optimization on iPhone OS, Part 2
WWDC2012 Session 242:iOS App Performance: Memory
iOS記憶體探秘