iOS記憶體淺談
iOS 記憶體機制特點
-
有限的可用記憶體
iPhone 裝置的 RAM 一直非常緊缺,iPhone 一代只有 128MB,直到 iPhone5 時達到了 1GB,並且在 iPhone7 plus 達到了 3GB。StackOverFlow 上提供了部分 iPhone 機型的可用記憶體數目。
-
低記憶體通知
在可用實體記憶體較少時,iOS 會給各應用發出低記憶體廣播通知,如果此後可用記憶體仍然低於特定值,則會殺死優先順序較低的程式。
-
沒有記憶體交換機制
桌面作業系統可以在實體記憶體緊張的時候把暫時不用的實體記憶體置換到磁碟上,並在需要的時候再次載入到記憶體中。而 iOS 沒有這種機制,原因是移動裝置的快閃記憶體沒有 PC 機那麼大的硬碟,而且頻繁的讀寫快閃記憶體會降低其壽命。目前 iOS 在記憶體不足時採用的方案是殺死優先順序較低的程式。
-
使用虛擬記憶體機制
和大多數桌面作業系統一樣,iOS 也使用虛擬記憶體機制。
虛擬記憶體
關於虛擬記憶體的原理和優缺點就不再累述,這裡說下 iOS 虛擬記憶體機制中與眾不同的地方。
記憶體分頁
iOS 把虛擬記憶體每 4KB 劃分成一個 Page,並不是所有的 Page 都會對映到實體記憶體中。每個 Page 有三種狀態:
-
Nonresident
是否 Resident 是一個 Page 狀態的重要標識,如果 Page 被對映到記憶體裡了,這個 Page 就是 Resident 狀態,否則就是 Nonresident 狀態;
-
Resident and clean
基於 readonly 檔案而被載入到記憶體中的 Page 稱為 clean memory,比如:系統 framework、可執行檔案、通過 mmap 方式讀取的檔案 等。這種 Page 由於是載入自不可變的檔案,因此可以在實體記憶體緊張時被 iOS 自動 unload 出去,並且在需要的時候再重新從原來的檔案載入到記憶體中。
-
Resident and dirty
凡是非 clean 的 Page 都是 dirty 的,它們的共同特點是 Page 在快閃記憶體中沒有對應的檔案,比如通過 alloc 在堆上建立的記憶體空間,已經解壓的圖片,database caches 等。dirty memory 不能被作業系統交換出去,只有在程式被殺死的時候才能被回收,因此在系統發生記憶體告警時,如果程式建立了大量的 dirty memory,那麼將很有可能被 kill 掉。
舉例說明
-
Malloc 分配記憶體
如前問所述,Malloc 的記憶體都是 Resident dirty 的,但事實上並非如此,比如:
1
|
char *p = valloc(2 * 4096); |
此時會在虛擬記憶體裡申請兩份 4096 位元組的記憶體,但由於申請後沒有使用,作業系統不會真正為剛申請的記憶體空間分配對應的實體記憶體空間,因此此時該記憶體空間處於 Nonresident 狀態。如果對 p[0] 賦值:
1
|
p[0] = 1; |
此時 P[0] 會被載入到實體記憶體上,由此變成 Resident dirty 狀態,同理如果對 p[1] 賦值也一樣。
-
mmap 載入檔案
一個檔案通過如果下述 mmap 方式載入:
1
|
NSData *data = [NSData dataWithContentsOfMappedFile:file];char *p = (char *)[data bytes]; |
此時檔案由於未被使用,因此也僅僅是在虛擬記憶體中,作業系統並沒有將其對映到物理裡,因此所屬 Page 的狀態是 Nonresident。如果呼叫以下程式碼:
1
|
printf( "%c" , p[0]); |
此時由於該檔案的 p[0] 部分被使用,作業系統就會將 p[0] 部分載入到實體記憶體中,又因為 p 對應的儲存區域是一個 mmap 方式載入的只讀檔案,因此 p[0] 對應的 Page 就是 Resident clean 的,而 p[1] 往後的部分由於仍然未被使用,Page 的狀態不變。
需要做什麼
對於開發者來說,要想減少應用因記憶體告警被系統殺掉,應做到以下幾點:
-
該儘可能減少 dirty 記憶體的建立
-
要儘量保證 dirty 記憶體用完之後及時釋放
-
及時處理系統記憶體告警通知,釋放掉大量佔用記憶體並且可重建的物件
-
在發生記憶體告警時,不再持續申請記憶體,更不能申請較大塊的記憶體
相關文章
- 淺談Java記憶體模型Java記憶體模型
- 淺談記憶體洩漏記憶體
- iOS記憶體管理淺析iOS記憶體
- 淺談Android記憶體優化Android記憶體優化
- v8記憶體分配淺談記憶體
- 淺談js的記憶體與閉包JS記憶體
- 淺談JVM記憶體分配與垃圾回收JVM記憶體
- 乾貨分享:淺談記憶體洩露記憶體洩露
- 淺談Linux記憶體管理機制Linux記憶體
- 淺談Linux的記憶體管理機制Linux記憶體
- 淺談SQL Server 對於記憶體的管理SQLServer記憶體
- 淺談JVM記憶體結構 和 Java記憶體模型 和 Java物件模型JVM記憶體Java模型物件
- 淺談作業系統對記憶體的管理作業系統記憶體
- iOS 記憶體管理iOS記憶體
- 談談CPU快取記憶體快取記憶體
- 電腦記憶體多大最好?談談電腦到底需要多大記憶體記憶體
- “理解”iOS記憶體管理iOS記憶體
- iOS 記憶體管理MRCiOS記憶體
- iOS 記憶體管理研究iOS記憶體
- 探索iOS記憶體分配iOS記憶體
- iOS arc 記憶體管理iOS記憶體
- 淺談記憶體、32位與64位系統的羈絆記憶體
- 淺談Android開發中記憶體洩露與優化Android記憶體洩露優化
- 淺談C#記憶體回收與Dispose﹐Close﹐Finalize方法[轉]C#記憶體
- iOS 淺談 RunloopiOSOOP
- 曹大談記憶體重排記憶體
- iOS 進階—— iOS 記憶體管理 & BlockiOS記憶體BloC
- 深入淺出記憶體馬(一)記憶體
- 深入淺出Java記憶體模型Java記憶體模型
- 【Java】 記憶體分配全面淺析Java記憶體
- Java 記憶體模型 JMM 淺析Java記憶體模型
- 淺析JVM記憶體分割槽JVM記憶體
- 資源供給:再談記憶體和虛擬記憶體記憶體
- 淺談快取寫法(三):記憶體快取該如何設計快取記憶體
- iOS微信記憶體監控iOS記憶體
- 探究 iOS 記憶體問題iOS記憶體
- iOS記憶體管理詳解iOS記憶體
- Weex-iOS 記憶體分析iOS記憶體