按照 session 的套路,我們先看一下提綱:
那我們就按順序開始啦!
記憶體是由系統管理,一般以頁為單位來劃分。在 ios 上,每一頁包含 16kb 的空間。一段資料可能會占用多頁記憶體,所占用頁總數乘以每頁空間得到的就是這段資料使用的總記憶體。
記憶體頁按照各自的分配和使用狀態,可以被分為clean
和dirty
兩類。
以上面的**為例,申請一塊長度為 80000 位元組的記憶體空間,按照一頁 16kb 來計算,就需要 6 頁記憶體來儲存。
如下圖所示,乙個 50kb 的被載入到記憶體中時,需要分配 4 頁記憶體來儲存。其中第四頁中有 2kb 的空間會被用來儲存這個的資料,剩餘空間可能會被用來儲存其它資料。
當記憶體不足的時候,系統會按照一定策略來騰出更多空間供使用,比較常見的做法是將一部分低優先順序的資料挪到磁碟上,這個操作稱為page out
。之後當再次訪問到這塊資料的時候,系統會負責將它重新搬回記憶體空間中,這個操作稱為page in
。
clean memory
dirty memory
值得注意的是,在使用 framework 的過程中會產生dirty memory
,使用單例或者全域性初始化方法是減少dirty memory
不錯的方法,因為單例一旦建立就不會銷毀,全域性初始化方法會在 class 載入時執行。
compressed memory
當記憶體吃緊的時候,系統會將不使用的記憶體進行壓縮,直到下一次訪問的時候進行解壓。
例如,當我們使用dictionary
去快取資料的時候,假設現在已經使用了 3 頁記憶體,當不訪問的時候可能會被壓縮為 1 頁,再次使用到時候又會解壓成 3 頁。
假設**中的cache
已被壓縮過
事實上,當你嘗試去再次訪問 cache 物件的時候,系統會先解壓這塊記憶體
這個過程中記憶體使用會增加,在記憶體吃緊的時候,這並不是我們想要的。隨後,當我們會執行大量工作去清空 cache,最終得到的記憶體空間和記憶體壓縮的結果一樣
所以,相比以往的快取手段,更加建議去調整策略,例如減少快取使用,或者在收到記憶體警告的時候,將這類事情交由系統去處理。
我們對資料進行快取的目的是想減少 cpu 的壓力,但是過多的快取又會占用過大的記憶體。由於記憶體壓縮機制的存在,我們需要根據快取資料大小以及重算這些資料的成本,在 cpu 和記憶體之間進行權衡。
在一些需要快取資料的場景下,可以考慮使用nscache
代替nsdictionary
,因為nscache
可以自動清理記憶體,在記憶體吃緊的時候會更加合理。
通常情況下,我們所說的記憶體占用是指dirty memory
和compressed memory
,clean memory
不需要過多關心。
當你使用 xcode 10 以前的版本進行除錯時,在記憶體過大時,debug session 會直接終止,並且在控制台列印出異常。從 xcode 10 開始,debugger 會自動捕獲exc_resource resource_type_memory
異常,並斷點在觸發異常丟擲的地方,十分方便定位問題。
通過這個工具,可以很直觀地檢視記憶體中所有物件的記憶體使用情況,以及相互之間的依賴關係,對定位那些因為迴圈引用導致的記憶體洩露問題十分有幫助。
簡單介紹一下相關的命令
vmmap - 檢視虛擬記憶體
檢視詳細報告
vmmap xx.memgraph檢視摘要報告
vmmap --summary xx.memgraph配合管道命令檢視所有動態庫的ditry pages的總和
vmmap -pages ***.memgraph | grep '.dylib' | awk ' end '只顯示cg image相關的資料
vmmap xx.memgraph | grep 'cg image'更多使用方式請檢視vmmap的文件
man vmmapleaks - 檢視****存
檢視是否有記憶體洩露
leaks xx.memgraph檢視某處記憶體的洩漏
leaks --tracetree [記憶體位址] xx.memgraph更多使用方式請檢視 leaks 的文件
man leaksheap - 檢視堆區記憶體
檢視所有堆區物件的記憶體使用
heap xx.memgraph預設情況下是按照物件數量進行排序,通常情況下它們不會造成什麼記憶體問題。我們需要關心的是那些為數不多,卻占用了大量記憶體的物件,這時候就可以增加引數
-sortbysize
,按照記憶體占用大小順序來檢視所有堆區物件的記憶體使用
heap xx.memgraph -sortbysize當確定是哪個型別的物件占用了太多記憶體之後,可以得到每個物件的記憶體位址
heap xx.memgraph -addresses all | 'xxbigdata'更多使用方式請檢視 heap 的文件
man heapenabling malloc stack logging
在product -> scheme -> edit scheme -> diagnostics
中,開啟malloc stack
功能,建議使用live allocations only
選項
之後 lldb 會記錄除錯過程中物件建立的堆疊,配合malloc_history
工具,就可以定位到那些占用了過大記憶體的物件是**建立的。
malloc_history - 檢視記憶體分配歷史
malloc_history xx.memgraph [address]
malloc_history xx.memgraph --fullstacks [address]更多使用方式請檢視 malloc_history 的文件
man malloc_history上面講述了那麼多的分析工具,那我們應該選擇哪種工具呢?蘋果的工程師幫我們做了如下整理:
大家可以根據上圖所示,根據不同的需要進行選擇。
對於 ios 系統而言,絕大部分場景下哪類資料佔記憶體最多呢?當然是!需要注意的是,所佔記憶體的大小與的尺寸有關,而不是的檔案大小。
例如:有乙個 590kb 的,解析度是 2048px * 1536px,它實際使用的記憶體不是 590kb,而是2048 * 1536 * 4 = 12 mb
。。
還有佔記憶體更小的格式:
選擇正確的格式可以減少了記憶體的使用。簡單總結一下:
乙個位元組:alpha 8
兩個位元組:亮度和alpha 8
四個位元組:srgb
八個位元組:wide 格式
複製**
那下乙個話題來了,如何選擇正確的格式呢?
簡單的回答是:不需要你來選擇格式,而是應該讓格式選擇你。是不是覺得一下子松了一口氣?哈哈?
用 uigraphicsimagerenderer 代替 uigraphicsbeginimagecontextwithoptions
使用uigraphicsbeginimagecontextwithoptions
生成的,每個畫素需要 4 個位元組表示。建議使用uigraphicsimagerenderer
,這個方法是從 ios 10 引入,在 ios 12 上會自動選擇最佳的影象格式,可以減少很多記憶體。
另外,如果想修改顏色,可以直接修改 tintcolor,不會有額外的記憶體開銷。
downsampling
當你縮小一幅影象的時候,會按照取平均值的辦法把多個畫素點變成乙個畫素點,這個過程稱為downsampling
。
uiimage 在設定和調整大小的時候,需要將原始影象加壓到記憶體中,然後對內部座標空間做一系列轉換,整個過程會消耗很多資源。我們可以使用 imageio,它可以直接讀取影象大小和元資料資訊,不會帶來額外的記憶體開銷。
記憶體是乙個有限的共享資源,要學會使用 xcode 分析記憶體工具,從而了解應用程式記憶體占用情況,並使用一些縮減應用程式記憶體占用空間的技巧和竅門。
ps:有理解認知不正確的,歡迎指正!
蘋果WWDC14 iOS8新特性
遊戲應用 遊戲優化,大型遊戲 3d場景so easy!metal 能夠減少opengl的負載,讓開發者更好的錄用裝置的晶元效能,從而大幅度提公升圖形和遊戲能力,讓之前無法在平板電腦上實現的情景成為了可能。spritekit 3d場景渲染器,專門針對休閒遊戲的以及3d遊戲的乙個優化,並且擁有更強的物理...
WWDC2014之iOS使用動態庫1
wwdc2014上發布的xcode6 beta版有了不少更新,其中令我驚訝的乙個是蘋果在ios上開放了動態庫,在xcode6 beta版的更新文件中是這樣描述的 在其它大部分平台上,動態庫都可以用於不同應用間共享,這就大大節省了記憶體。從目前來看,ios仍然不允許程序間共享動態庫,即ios上的動態庫...
ios 內購資料
如果您正在尋找乙份手把手教你實現iap的教程的話,這篇文章不是您的菜。關於iap的實現和步驟,可以參考下面的教程 和相應的 ray wenderlich的 一篇 並茂的 中文教程 直接使用大神們封好的store有關的庫,比如 mattt cargobay robotmedia rmstore 或者m...