1.Memory Graph是什么
Memory Graph
是在Xcode8
上推出的一個(gè)新特性句柠。用來(lái)生成應(yīng)用程序中對(duì)象分配的內(nèi)存圖浦译。
2.Memory Graph用來(lái)做什么
-
Memory Graph
可以幫助我們找到循環(huán)引用和內(nèi)存泄漏棒假,正在使用的內(nèi)存以及每個(gè)區(qū)域的大小。 -
Memory Graph
顯示應(yīng)用程序使用的內(nèi)存的位置精盅,以及這些使用內(nèi)存之間的引用關(guān)系帽哑。
3.如何使用Memory Graph
打開配置
注意點(diǎn):
啟用
Malloc Stack
后,Memory Graph
會(huì)顯示分配該節(jié)點(diǎn)時(shí)記錄的堆棧跟蹤叹俏。使用此信息將Memory Graph
中的內(nèi)存分配與源代碼中的函數(shù)和方法相關(guān)聯(lián)妻枕。如果沒(méi)有勾選Malloc Stack
在調(diào)試的時(shí)候,在右側(cè)是看不到調(diào)用的堆棧信息。勾選
Malloc Stack
之后內(nèi)存會(huì)相應(yīng)的增高屡谐,如果不調(diào)試可以關(guān)閉該選項(xiàng)述么。建議選擇
Live Allocations Only
如果選擇All Allocations and Free History
會(huì)出現(xiàn)一些額外的影響因素。
打開方式
通過(guò)單擊Xcode
工作區(qū)底部調(diào)試區(qū)域中的 Debug Memory Graph
按鈕來(lái)生成應(yīng)用程序中對(duì)象和分配的內(nèi)存圖愕掏。
點(diǎn)擊`Debug Memory Graph`暫停應(yīng)用執(zhí)行度秘,展示如下:
- 在左側(cè)
debug navigator
展示了app的heap contents
。 - 在中間部分是對(duì)象的引用關(guān)系饵撑。
- 在最右側(cè)是展示了當(dāng)前對(duì)象的調(diào)用椊J幔回溯。
Memory Graph
顯示應(yīng)用程序正在使用的內(nèi)存區(qū)域以及每個(gè)區(qū)域的大小滑潘。圖中的節(jié)點(diǎn)代表一個(gè)對(duì)象(object
)垢乙、一個(gè)堆分配(heap allocation
)或內(nèi)存映射文件(memory-mapped file
)。節(jié)點(diǎn)之間的連接语卤,通過(guò)箭頭連接追逮,顯示一個(gè)內(nèi)存區(qū)域引用另一個(gè)對(duì)象。
Tips:
為了幫助我們更快的分析內(nèi)存泄漏粹舵,我們可以在左側(cè)的debug navigator
進(jìn)行篩選只展示leaks的內(nèi)容羊壹。
可以將我們生成的memory graph進(jìn)行導(dǎo)出,選擇 file
> export Memory Graph
共享給團(tuán)隊(duì)內(nèi)的人員使用和分析探索齐婴。我們還可以使用命令行工具進(jìn)行分析油猫,主要的指令有leaks
、heap
柠偶、vmmap
情妖、malloc_history
等。
4.項(xiàng)目實(shí)際應(yīng)用及分析
導(dǎo)出所對(duì)應(yīng)的Memory Graph
使用命令行的形式進(jìn)行分析诱担。主要分析內(nèi)存泄漏
和大內(nèi)存
占用毡证。
Memory FootPrint
Apple推薦我們使用FootPrint命令查看一個(gè)進(jìn)程占用的大小。關(guān)于什么是 footprint蔫仙,在官方文檔 Minimizing your app’s Memory Footprint 里有說(shuō)明:
FootPrint = Dirty memory + Swapped memory(Compressed memory)
Refers to the total current amount of system memory that is allocated to your app.
iOS中內(nèi)存分為兩種:
-
Clean memory
- 內(nèi)存映射文件(Memory mapped files )
- 數(shù)據(jù)段常量/代碼段數(shù)據(jù) (System Frameworks)
-
Dirty memory
(堆上分配的內(nèi)存) All heap allocations
(解碼圖像緩沖區(qū)) Decoded image buffers
-
Frameworks
Clean memory
在系統(tǒng)內(nèi)存緊張的時(shí)候可以從page中換出料睛,當(dāng)再次訪問(wèn)的時(shí)候可以從磁盤中進(jìn)行讀取。Dirty memory
是無(wú)法換出的
在iOS7時(shí)Apple引入了Compressed memory 摇邦,即系統(tǒng)可以把最近最少使用的Dirty memory進(jìn)行壓縮恤煞,這樣可以騰出一些pages供使用,當(dāng)再次需要訪問(wèn)內(nèi)容時(shí)施籍,系統(tǒng)將其解壓居扒,這時(shí),原來(lái)內(nèi)容占多少pages丑慎,解壓后同樣會(huì)是相同數(shù)量的pages
1.內(nèi)存分析
先通過(guò)vmmap看一下內(nèi)存的摘要圖:
vmmap -summary memGraph.memgraph
-
從這個(gè)圖中可以看到當(dāng)前app的一個(gè)內(nèi)存分布情況喜喂,
footPrint
占用的內(nèi)存大小為26.1M瓤摧,根據(jù)footprint
的計(jì)算方式可以知道,我們需要關(guān)注的是dirty size + swapped size
這兩列的數(shù)據(jù)玉吁。首先看下對(duì)應(yīng)的Region type
分別代表的是什么內(nèi)存照弥。- CG raster data(光柵化數(shù)據(jù),也就是像素?cái)?shù)據(jù)进副。注意不一定是圖片产喉,一塊顯示緩存里也可能是文字或者其他內(nèi)容。通常每像素消耗 4 個(gè)字節(jié))
- Image IO敢会、IOSurface(圖片編解碼緩存)
- maclloc_ 開頭的是我們自己通過(guò)malloc進(jìn)行創(chuàng)建的內(nèi)存占用曾沈。這部分內(nèi)存在所謂的Heap上。
- IOSurface 在CoreGraphics鸥昏、OpenGLES塞俱、Metal之間傳遞紋理數(shù)據(jù)。簡(jiǎn)單理解為IOSurface吏垮,為CPU和GPU直接搭建了?個(gè)傳遞紋理數(shù)據(jù)的橋梁障涯。
那么看下具體的是哪些類占用了內(nèi)存。需要具體來(lái)分析一下膳汪。
從里面看到都是CG raster data 占用比較大唯蝶。具體在哪里被引用了,需要看一下具體的調(diào)用棧遗嗽。首先篩選出來(lái)CG raster data的內(nèi)存信息粘我,包括它的地址、尺寸以及所在Heap Zone等等信息痹换。我們可以在這里找到我們的目標(biāo)征字。
vmmap memGraph.memgraph | grep 'CG raster data'
malloc_history -fullStacks memGraph.memgraph 0x10ee24000
通過(guò)vmmap
篩除所有關(guān)于CG raster data
內(nèi)存情況。然后通過(guò)malloc_history -fullStacks
拿到對(duì)象的詳細(xì)調(diào)用堆棧娇豫。
可以看出是在SDWebImage對(duì)圖片的解碼數(shù)據(jù)做了緩存匙姜。建議在使用的時(shí)候設(shè)置緩存的圖片數(shù)量和大小。也可以根據(jù)具體的情況關(guān)掉解碼的緩存冯痢〉粒或者在加載大圖的時(shí)候使用ImageIO
的形式進(jìn)行加載。
2.內(nèi)存泄漏
通過(guò)leaks篩除所有的內(nèi)存泄漏
leaks memGraph.memgraph
從上圖中可以看出浦楣,是AFHttpSessionManager
出現(xiàn)了內(nèi)存泄漏袖肥,從引用的關(guān)系中可以看出,是當(dāng)前的sessionManager
強(qiáng)引用了session
椒振,session
的delegate
同時(shí)強(qiáng)引用了sessionManager
昭伸。解決方案就是我們?cè)谡{(diào)用之前使用weak弱引用sessionManager
梧乘,當(dāng)請(qǐng)求完成的時(shí)候執(zhí)行finishTasksAndInvalidate
澎迎。