隨著用戶的增長(zhǎng)贿肩,用戶使用時(shí)間的延長(zhǎng)座哩,APP的內(nèi)存問(wèn)題會(huì)變得越發(fā)嚴(yán)重苍凛。今年WWDC大會(huì)趣席,有個(gè)專門的session,深入解析iOS內(nèi)存醇蝴。
我是寫了iOS內(nèi)存分析上-圖片加載內(nèi)存分析后看到了這個(gè)session宣肚,發(fā)現(xiàn)大致的思路相同,都是從實(shí)用角度分析怎么減少內(nèi)存消耗悠栓、footprint測(cè)量霉涨、圖片內(nèi)存占用分析幾個(gè)角度。session中的講解更加詳盡一些闸迷,本文嘗試整理session內(nèi)容嵌纲,并會(huì)增加一些自己的理解。
一腥沽、Why reduce memory
1 為什么要減少內(nèi)存消耗逮走?
APP加載更快,系統(tǒng)更流暢今阳,APP的內(nèi)存駐留時(shí)間更長(zhǎng)师溅,其他APP的內(nèi)存駐留時(shí)間更長(zhǎng)……總之,一句話:
為了更好的用戶體驗(yàn)
2.減小哪一部分的內(nèi)存消耗盾舌?
不是所有的內(nèi)存都是同等的墓臭,我們?cè)趇OS開(kāi)發(fā)中,需要關(guān)注的內(nèi)存消耗是:
Memory Footprint
二妖谴、Memory Footprint
1.Memory Pages
系統(tǒng)是按頁(yè)分配內(nèi)存的窿锉,每個(gè)page通常是16KB,APP消耗的內(nèi)存就是:
Memory in use = Number of pages * Page size
iOS內(nèi)存可以分為clean memory和dirty memory膝舅。當(dāng)用戶(也就是程序員)申請(qǐng)分配內(nèi)存時(shí)嗡载,系統(tǒng)只會(huì)對(duì)這塊內(nèi)存進(jìn)行標(biāo)記,這時(shí)只會(huì)分配虛擬內(nèi)存仍稀,而不會(huì)分配物理內(nèi)存洼滚,此時(shí)內(nèi)存是clean memory。當(dāng)對(duì)這塊內(nèi)存進(jìn)行數(shù)據(jù)填充時(shí)技潘,才會(huì)分配物理內(nèi)存遥巴,內(nèi)存變?yōu)閐irty memory千康。
example code:
int *array = malloc(20000 * sizeof(int));
array[0] = 32;
array[19999] = 64;
首先分配了20k的int,需要6個(gè)page铲掐,分別對(duì)page0和page5寫入數(shù)據(jù)后拾弃,這兩個(gè)page變?yōu)榱薲irty memory,而page1~4這4個(gè)page仍然是clean memory摆霉。
2.內(nèi)存模型
提出了一個(gè)內(nèi)存分級(jí)模型
Dirty Memory
Compressed
Clean Memory
Clean Memory
就是可以從內(nèi)存中換頁(yè)出去的內(nèi)存(can be paged out of Memory)砸彬。可以是:Memory-mapped files(image.jpeg, blob.data, training.model), frameworks*(__DATA_CONST)
一些運(yùn)行時(shí)的用法斯入,如swizz,會(huì)將以上所說(shuō)的framework中的clean memory蛀蜜,變?yōu)閐irty memory
Dirty Memory
是APP寫入的內(nèi)存刻两。可以是:All heap allocations, decoded image buffers, frameworks
特別指出滴某,由于單例創(chuàng)建后會(huì)常駐內(nèi)存磅摹,全局initialize在load或者link后就會(huì)運(yùn)行,可以一定程度上減少dirty memory霎奢。
+ (void)load; // Objective-c
+ (void)initialize; // Objective-c
__attribute__((constructor)) // Objective-c
initialize(); // swift
Compressed Memory
iOS系統(tǒng)中沒(méi)有磁盤交換系統(tǒng)(disk swap system户誓,就是傳統(tǒng)的PC端的虛擬內(nèi)存),而是在iOS7開(kāi)始引入了內(nèi)存壓縮(Memory compressor)幕侠。
它會(huì)將未訪問(wèn)的頁(yè)(unaccessed pages)進(jìn)行壓縮帝美,從而獲得更多的內(nèi)存空間,并在訪問(wèn)頁(yè)時(shí)晤硕,進(jìn)行解壓縮悼潭。
3.內(nèi)存警告
內(nèi)存警告未必是由于前臺(tái)APP導(dǎo)致的。比如舞箍,當(dāng)設(shè)備在低內(nèi)存時(shí)舰褪,打過(guò)來(lái)一通電話,就可能會(huì)出發(fā)內(nèi)存警告疏橄。同時(shí)占拍,由于Compressed Memory的存在,內(nèi)存警告時(shí)的策略需要有多重情況的策略設(shè)計(jì)捎迫,避免為了釋放內(nèi)存而訪問(wèn)了compressed內(nèi)存晃酒,導(dǎo)致內(nèi)存使用更加惡劣,最終OOM立砸。
推薦使用NSCache掖疮,有系統(tǒng)內(nèi)存feature的優(yōu)化。
4.Memory Footprint
有了上面的儲(chǔ)備知識(shí)后颗祝,可以通過(guò)以下公式進(jìn)行內(nèi)存優(yōu)化
Memory Footprint = Dirty Memory + Compressed Memory
也就是通常的APP浊闪,不需要關(guān)注Clean Memory恼布,使用NSCache進(jìn)行緩存,也可以不過(guò)多關(guān)注Compressed Memory搁宾。重點(diǎn)關(guān)注Dirty Memory折汞。
5.Memory Footprint Limit
Memory Footprint 限制是根據(jù)設(shè)備變更的,不同的設(shè)備的上限不同盖腿。
APP 的Memory Footprint Limit上限比較高
Extention的Memory Footprint Limit上限比較低
以及Xcode 10可以捕獲內(nèi)存超限的事件 EXC_RESOURCE_EXCEPTION爽待。emmm,所以是做了llvm優(yōu)化翩腐,使得能夠進(jìn)行相關(guān)事件的捕獲鸟款?期待iOS12發(fā)布,Xcode10打包茂卦,之后就可以順理成章拋棄iOS8何什,迎接新特性,走向人生巔峰了等龙。