DEAD in iOS Memory

虛擬內(nèi)存的來由

一個(gè)系統(tǒng)中的進(jìn)程是與其他進(jìn)程共享CPU和主存資源的,最開始我們直接訪問物理內(nèi)存地址,但是后來我們發(fā)現(xiàn)會(huì)造成各種各樣的問題:

  1. 地址空間不隔離
    所有的進(jìn)程都可以直接訪問物理地址,那表明各個(gè)進(jìn)程的內(nèi)存空間不是互相隔離的。有些惡意的進(jìn)程或者被注入惡意代碼的進(jìn)程非常容易去改寫其他進(jìn)程的內(nèi)存數(shù)據(jù),以達(dá)到破壞的目的。
  2. 內(nèi)存使用效率低
    由于沒有有效的內(nèi)存管理機(jī)制,需要一個(gè)程序執(zhí)行時(shí),會(huì)將整個(gè)程序裝入內(nèi)存中然后開始執(zhí)行。如果我們這個(gè)時(shí)候突然想要運(yùn)行另外一個(gè)程序,那么很可能遇到內(nèi)存空間不足。這時(shí)候有一種處理方法是將其他程序的數(shù)據(jù)暫時(shí)寫到磁盤里面,等到用的時(shí)候再讀回來。由于程序所需要的空間是連續(xù)的,那么在這個(gè)方法里,如果我們將程序A換出到磁盤所釋放的內(nèi)存空間是不夠的,所以接著會(huì)將程序B換出到磁盤,然后將程序C讀入到內(nèi)存開始運(yùn)行。我們可以看出來,整個(gè)過程中有大量的數(shù)據(jù)在換入換出,導(dǎo)致效率十分低下。
  3. 程序運(yùn)行的地址不確定
    因?yàn)槌绦蛎看涡枰b入運(yùn)行時(shí),我們需要給它從內(nèi)存中分配一塊足夠大的空閑區(qū)域,這個(gè)空閑區(qū)域的位置是不確定的。這給程序員的編寫造成了一定的麻煩,因?yàn)槌绦蛟诰帉憰r(shí),它訪問數(shù)據(jù)和指令跳轉(zhuǎn)的目標(biāo)地址很多都是固定的,需要重定向。

這時(shí)候,就產(chǎn)生了一種解決方案,一種對(duì)主存的抽象概念,叫做 虛擬內(nèi)存(Virtual Memory/VM,下文中為了簡(jiǎn)便可能會(huì)使用縮寫) 。

虛擬內(nèi)存的作用

虛擬內(nèi)存是硬件異常、硬件地址翻譯、主存、磁盤文件和內(nèi)核軟件的完美交互,它為每個(gè)進(jìn)程提供了一個(gè)大的、一致的和私有的地址空間。
虛擬內(nèi)存提供可三個(gè)重要的功能:

  1. 它將主存看成是一個(gè)存儲(chǔ)在磁盤上的地址空間的高速緩存,在主存中只保存活動(dòng)區(qū)域,并根據(jù)需要在磁盤和主存之間來回傳送數(shù)據(jù);
  2. 它為每個(gè)進(jìn)程提供了一致的地址空間,從而簡(jiǎn)化了內(nèi)存管理;
  3. 它保護(hù)了每個(gè)進(jìn)程的地址空間不被其他進(jìn)程破壞。

VM是沉默的工作,不需要開發(fā)人員的任何干涉。但是,我們依然要注意它,原因有三:

  1. 虛擬內(nèi)存是核心的
    VM遍及計(jì)算機(jī)系統(tǒng)的所有層面,在硬件異常、匯編器、鏈接器、加載器、共享對(duì)象、文件和進(jìn)程的設(shè)計(jì)中扮演著重要的角色。理解VM將幫助開發(fā)者更好的理解系統(tǒng)通常是如何工作的。(尤其是在iOS開發(fā)中?。?/li>
  2. 虛擬內(nèi)存是強(qiáng)大的
    VM給予了應(yīng)用程序強(qiáng)大的能力,可以創(chuàng)建和銷毀內(nèi)存片、將內(nèi)存片映射到磁盤文件中的某個(gè)部分(mmap),以及與其他進(jìn)程共享內(nèi)存。理解VM將幫助你利用它的強(qiáng)大功能在應(yīng)用程序中添加動(dòng)力。
  3. 虛擬內(nèi)存是危險(xiǎn)的
    每次應(yīng)用程序引用一個(gè)變量、間接引用一個(gè)指針,或者調(diào)用一個(gè)諸如malloc這樣的動(dòng)態(tài)分配程序時(shí),它就會(huì)和VM發(fā)生交互。如果VM使用不當(dāng),應(yīng)用將遇到復(fù)雜危險(xiǎn)的與內(nèi)存有關(guān)的錯(cuò)誤。理解VM可以幫助開發(fā)者規(guī)避這種錯(cuò)誤。

尋址方式

計(jì)算機(jī)系統(tǒng)的主存被組織成一個(gè)由M個(gè)連續(xù)的字節(jié)大小的單元組成的數(shù)組。每個(gè)字節(jié)都有一個(gè)唯一的物理地址(Physical Address)。第一個(gè)字節(jié)的地址為0,下一個(gè)為1,在往下是2,以此類推。直接通過物理地址訪問內(nèi)存的方法就是 物理尋址。原理 如下圖:

image

而現(xiàn)在除了嵌入式設(shè)備和某些超級(jí)計(jì)算機(jī)意外,我們使用 虛擬尋址來取代物理尋址。
使用虛擬尋址,CPU通過生成一個(gè)虛擬地址(VIrtual Address)來訪問主存,這個(gè)虛擬地址在被送到內(nèi)存前先轉(zhuǎn)換成適當(dāng)?shù)奈锢淼刂?。將虛擬地址轉(zhuǎn)換成物理地址的任務(wù)叫做地址翻譯。原理 如下圖:
image

注:MMU(Memory Management Unit,內(nèi)存管理單元),CPU上的一個(gè)專用硬件,用來存放在主存中的查詢表來動(dòng)態(tài)翻譯虛擬地址。

地址空間

地址空間是一個(gè)線性的非負(fù)整數(shù)地址的有序集合:
如果像是{0,1,2,……}一樣,我們可以稱之為線性地址空間。
分為虛擬地址空間和物理地址空間,分別對(duì)應(yīng)虛擬內(nèi)存和物理內(nèi)存。
地址空間幫助我們區(qū)分了數(shù)據(jù)對(duì)象(字節(jié))和它們的屬性(地址)。主存中的每字節(jié)都有一個(gè)選自虛擬空間的虛擬地址和一個(gè)選自物理空間的物理地址。

(注意,這里只講了頁式虛擬內(nèi)存,還有另外一種段式虛擬內(nèi)存,也可以把頁式當(dāng)成一種特殊的段式)

現(xiàn)代操作系統(tǒng)將內(nèi)存劃分為頁,來簡(jiǎn)化內(nèi)存管理,一個(gè)頁其實(shí)就是一段連續(xù)的內(nèi)存地址的集合,通常有 4k 和 16k(iOS 64 位是 16K)的,成為 Virtual Page 虛擬頁。與之對(duì)應(yīng)的物理內(nèi)存被稱為 Physical Page 物理頁。
注意 虛擬頁的個(gè)數(shù)可能和物理頁個(gè)數(shù)不一樣 比如說一個(gè) 64 位操作系統(tǒng)中使用 48 位地址空間的 虛擬頁大小為 16K,那么其虛擬頁可數(shù)可達(dá)到(2^48 / 2^14 = 16M 個(gè))假設(shè)物理內(nèi)存只有 4G 那么物理頁可能只有 (2^32 / 2^14 = 256k 個(gè))。
任何時(shí)刻,虛擬頁面的集合都分為三個(gè)不想交的子集:

  1. 未分配的:VM系統(tǒng)還未分配的(或者創(chuàng)建)的頁。未分配的塊沒有任何數(shù)據(jù)和它們相關(guān)聯(lián),因此也就不占用任何磁盤空間。
  2. 緩存的:當(dāng)前已緩存在物理內(nèi)存中的已分配頁。
  3. 未緩存的:未緩存在物理內(nèi)存中的已分配頁。

DRAM中的結(jié)構(gòu)

我們用SRAM(靜態(tài)RAM)來表示L1、L2和L3高速緩存,用DRAM(動(dòng)態(tài)RAM)表示虛擬內(nèi)存中的緩存(它在主頁中緩存虛擬頁)。
在緩存中,DRAM未命中比SRAM要昂貴的多,因?yàn)镾RAM未命中可以有DRAM來兜底,DRAM未命中就需要用磁盤來兜底(磁盤要比DRAM慢100000多倍,而且從磁盤的一個(gè)扇區(qū)讀取第一個(gè)字節(jié)的時(shí)間開銷比讀連續(xù)的字節(jié)要慢非常非常多)。因?yàn)樯厦娴脑颍摂M頁往往設(shè)置的比較大,通常4KB-2MB。而且,DRAM是全相聯(lián)的, 任何虛擬頁都可以放置在任何物理頁之中。

image

頁表

操作系統(tǒng)使用頁表(PageTable),將虛擬頁映射到物理頁。每次地址翻譯硬件將一個(gè)虛擬地址轉(zhuǎn)換為物理地址時(shí),都會(huì)讀取頁表。
頁表實(shí)際上是一個(gè)頁表?xiàng)l目(Page Table Entry,PTE)的數(shù)組。虛擬地址空間中的每個(gè)頁在頁表中一個(gè)固定偏移處都有一個(gè)PTE。結(jié)構(gòu)如下:


image

缺頁

假如DRAM緩存未命中,被稱之為缺頁(page fault)。當(dāng)缺頁發(fā)生時(shí),會(huì)啟動(dòng)內(nèi)核中的缺頁異常程序,選擇一個(gè)犧牲頁,進(jìn)行磁盤和內(nèi)存中數(shù)據(jù)的交換。
在iOS系統(tǒng)中,因?yàn)閮?nèi)存的緊張,并未采用這種方式,而是類似OOM警告的方式來控制,MacOS中是存在的。

虛擬內(nèi)存的內(nèi)存管理

VM為每個(gè)進(jìn)程都提供了一個(gè)獨(dú)立的頁表,因而也就是一個(gè)獨(dú)立的虛擬地址空間。使用VM也會(huì)有很多優(yōu)點(diǎn)

  1. 簡(jiǎn)化鏈接
    每個(gè)獨(dú)立的地址空間允許每個(gè)進(jìn)程的內(nèi)存映像使用相同的基本格式,而不管代碼和數(shù)據(jù)實(shí)際存放在物理內(nèi)存的何處。
  2. 簡(jiǎn)化加載
    VM使得容易向內(nèi)存中加載可執(zhí)行文件和共享對(duì)象文件。
  3. 簡(jiǎn)化共享
    獨(dú)立的地址空間為操作系統(tǒng)提供了一個(gè)管理用戶進(jìn)程和操作系統(tǒng)自身之間共享的一致機(jī)制。
  4. 簡(jiǎn)化內(nèi)存分配
    假如遇到需要共享內(nèi)存數(shù)據(jù)的時(shí)候,VM機(jī)制可以幫助我們有選擇的訪問共享頁面。

內(nèi)存保護(hù)

我們應(yīng)該明白,不應(yīng)該允許一個(gè)用戶進(jìn)程任意修改它的只讀代碼段;不允許修改內(nèi)核的代碼和數(shù)據(jù)結(jié)構(gòu);不允許讀寫其他進(jìn)程的私有內(nèi)存。
為了提供這種保護(hù),地址翻譯機(jī)制會(huì)在讀取PTE的時(shí)候,添加一些額外的許可位來控制虛擬頁面。如下圖所示:


image

地址翻譯

image

n位的虛擬地址包含兩個(gè)部分:p位的虛擬頁面偏移(VPO)和一個(gè)(n-p)位的虛擬頁號(hào)(VPN)。MMU使用VPN來選擇適當(dāng)?shù)腜TE。
這里詳細(xì)細(xì)節(jié)查看《深入理解計(jì)算機(jī)系統(tǒng)》(第三版)p568-p570

TLB

每次CPU產(chǎn)生一個(gè)地址,MMU就必須查閱一個(gè)PTE,以便將虛擬地址翻譯成為物理地址。這會(huì)造成非常大的性能損耗。如何解決呢?答案簡(jiǎn)單,使用緩存!我們?cè)谶@里使用一個(gè)叫做 翻譯后備緩沖器(Transalation Lookaside Buffer-TLB)的東西來幫助我們處理。當(dāng)TLB未命中時(shí),MMU再去L1緩存中獲取對(duì)應(yīng)的PTE,然后再將它放到TLB中。

多級(jí)頁表

一般來說,系統(tǒng)的地址空間也是有限的,我們不能每次都要一起訪問整個(gè)頁表。這里我們可以使用 多級(jí)頁表技術(shù)。
一級(jí)頁表對(duì)應(yīng)二級(jí)頁表,二級(jí)頁表對(duì)應(yīng)虛擬內(nèi)存頁面。我們只要把一級(jí)頁表一直放到主存中就好了,需要的時(shí)候再去訪問二級(jí)頁表。

Linux中的虛擬內(nèi)存

操作系統(tǒng)為每個(gè)進(jìn)程維護(hù)一個(gè)單獨(dú)的虛擬地址空間,分為兩部分。

  • 內(nèi)核虛擬內(nèi)存
    包含內(nèi)核中的代碼和數(shù)據(jù)結(jié)構(gòu),還有一些被映射到所有進(jìn)程共享的內(nèi)存頁面。還有一些頁表,內(nèi)核在進(jìn)程上下文中執(zhí)行代碼使用的棧。
  • 進(jìn)程虛擬內(nèi)存
    OS 將內(nèi)存組織為一些區(qū)域(Sement)的集合,代碼端,數(shù)據(jù)端,共享庫端,線程棧都是不同的區(qū)域,分段的原因是便于管理內(nèi)存的權(quán)限,如果了解過 Mach-O 文件或者 ELF 文件的讀者可以看到相同的 Segment 里面的內(nèi)存權(quán)限是相同的,每個(gè) Segment 再劃分不同的內(nèi)容為 section。
一個(gè)Linux進(jìn)程的虛擬內(nèi)存

內(nèi)存映射 (mmap)

在Linux中,通過將一個(gè)虛擬內(nèi)存區(qū)域與一個(gè)磁盤上的對(duì)象關(guān)聯(lián)起來,以初始化這個(gè)虛擬內(nèi)存區(qū)域的內(nèi)容。

大致過程如下:進(jìn)程先在虛擬地址空間中創(chuàng)建虛擬映射區(qū)域,然后內(nèi)核開始調(diào)用mmap函數(shù),實(shí)現(xiàn)物理地址和虛擬地址的映射。

實(shí)現(xiàn)細(xì)節(jié)可以查看 《深入理解計(jì)算機(jī)系統(tǒng)》(第三版)p582-p586

我們需要記住:mmap為共享書、創(chuàng)建新的進(jìn)程以及加載程序提供了一個(gè)高效的機(jī)制。應(yīng)用可以使用mmap函數(shù)來手工德創(chuàng)建和刪除虛擬地址空間區(qū)域內(nèi)一個(gè)稱謂堆(heap)的區(qū)域。
而mmap在iOS的用處:

  1. mmap 讓讀寫一個(gè)文件像操作一個(gè)內(nèi)存地址一樣簡(jiǎn)單方便,
  2. mmap 效率極高,不用將一個(gè)內(nèi)容從磁盤讀入內(nèi)核態(tài)再拷貝至用戶態(tài)
  3. mmap映射的文件由操作系統(tǒng)接管,如果進(jìn)程 Crash 操作系統(tǒng)會(huì)保證文件刷新回磁盤。

通過以上的特點(diǎn),我們可以在圖片加載(例如FastImageCache),數(shù)據(jù)存儲(chǔ)以及關(guān)鍵的crash收集上報(bào)中使用。

動(dòng)態(tài)內(nèi)存分配

在運(yùn)行時(shí)需要額外的虛擬內(nèi)存的時(shí)候,用動(dòng)態(tài)內(nèi)存分配器更方便、更好的可移植性。
動(dòng)態(tài)內(nèi)存分配器維護(hù)著一個(gè)進(jìn)程的虛擬內(nèi)存區(qū)域,稱之為 。堆可以被視為一組大小不同的塊(block)的集合。這些塊要不然就是分配的,要不然就是空閑的。
分配器有兩種基本風(fēng)格,兩種風(fēng)格都要求顯式的分配塊:

  • 顯式分配器 (手動(dòng)管理內(nèi)存,嚴(yán)格來講ARC算是這個(gè)的變種)
  • 隱式分配器 (垃圾收集,Java等語言采用這種)

顯示分配器的實(shí)現(xiàn)細(xì)節(jié)可以查看 《深入理解計(jì)算機(jī)系統(tǒng)》(第三版)p587-p605。十分推薦iOS去讀,很多時(shí)候跳出來看一下原理,會(huì)讓自己有新的認(rèn)知。
隱式分配器或者說垃圾收集實(shí)現(xiàn)細(xì)節(jié)可以查看 《深入理解計(jì)算機(jī)系統(tǒng)》(第三版)p605-p609
因?yàn)槲覍?duì)使用GC的語言的語言沒什么研究,兩者的區(qū)別優(yōu)劣我無法給出,不過推薦一下這篇文章Garbage Collection vs Automatic Reference Counting。
傾寒推薦這個(gè)代碼C + + 實(shí)現(xiàn)一個(gè)簡(jiǎn)易的內(nèi)存池分配器,也可以看一下。

iOS Memory

在上邊我們了解的頁這一概念,iOS實(shí)際上也是使用了這一概念。
我們使用以下代碼來查看數(shù)據(jù)

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "mach/mach.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        printf("page-size:%ld \nmask:%ld\nshift:%d \n", vm_kernel_page_size, vm_kernel_page_mask, vm_kernel_page_shift);
        printf("%ld\n", sysconf(_SC_PAGE_SIZE));
        printf("%d\n", getpagesize());
        printf("%lu\n", PAGE_SIZE);
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

得到的數(shù)據(jù)為(iPhone 8 plus和iPhone SE):

page-size:16384 
mask:16383
shift:14 
16384
16384
16384 = 16kb

我們用過以上數(shù)據(jù)可以得知:頁大小為16kb,虛擬地址偏移為14。這里即使用上文中提過的TLB來翻譯地址。
在我們未寫入數(shù)據(jù),但是剛剛被操作系統(tǒng)分配或者磁盤映射的時(shí)候,內(nèi)存都是出于 Clean的狀態(tài),但是一旦被寫入了沒操作系統(tǒng)會(huì)將它標(biāo)記為 Dirty。

  • Clean:指的是能夠被系統(tǒng)清理出內(nèi)存并且在有需要的時(shí)候重新加載的數(shù)據(jù),包括:Memory mapped files;Frameworks中的__DATA_CONST部分;應(yīng)用的二進(jìn)制可執(zhí)行文件。
  • Dirty:指的是不能被系統(tǒng)回收的內(nèi)存占用,包括:堆上的對(duì)象;圖片解碼數(shù)據(jù);Frameworks中的__DATA和__DATA_DIRTY部分。

標(biāo)記的一個(gè)好處在于:因?yàn)镈irty頁面已經(jīng)被寫入數(shù)據(jù),是要比Clean重要的多的。當(dāng)操作系統(tǒng)發(fā)現(xiàn)內(nèi)存十分緊張的時(shí)候,會(huì)嘗試驅(qū)逐一部分內(nèi)存頁面。Clean的頁面會(huì)因?yàn)閮?yōu)先級(jí)的原因被首先驅(qū)逐,并開始和磁盤(中的backing store部分)交換分區(qū),等到需要使用的時(shí)候再去讀取。
但是我們這里要注意一點(diǎn),iOS因?yàn)槭窃谝苿?dòng)端使用,移動(dòng)端使用的是閃存?,F(xiàn)在新版的iPhone使用的都是TLC(Triple-Level Cell),過于頻繁的讀寫會(huì)嚴(yán)重影響閃存的使用壽命(實(shí)際上是二氧化硅薄膜因?yàn)殡娮拥念l繁進(jìn)出而變?。K圆]有使用上邊這個(gè)磁盤交換機(jī)制,因此如果出現(xiàn)內(nèi)存緊張的情況,iOS會(huì)使用Compressed Memory機(jī)制。在內(nèi)存緊張的時(shí)候,將不常使用的內(nèi)存壓縮并且在需要的時(shí)候解壓。

When your system’s memory begins to fill up, Compressed Memory automatically compresses the least recently used items in memory, compacting them to about half their original size. When these items are needed again, they can be instantly uncompressed.

這個(gè)舉措,特點(diǎn)可以歸納為:

  • 減少了不活躍內(nèi)存占用
  • 改善了電源效率,通過壓縮減少磁盤IO帶來的損耗
  • 壓縮/解壓十分迅速,能夠盡可能減少 CPU 的時(shí)間開銷
  • 支持多核操作

從某種意義上來說,我們可以把Compressed memory視為Dirty memory。


image

memory footprint = dirty size + compressed size ,這也就是我們需要并且能夠嘗試去減少的內(nèi)存占用
當(dāng)我們的app的memory footprint 達(dá)到一定的值時(shí),我們會(huì)受到內(nèi)存警告(Memory Warnings)。
如果我們收到了內(nèi)存警告,系統(tǒng)本身會(huì)釋放一部分內(nèi)存頁面(例如NSCache機(jī)制),但是也會(huì)向當(dāng)前運(yùn)行的程序發(fā)送低內(nèi)存警告,我們也要對(duì)此作出相應(yīng)。
UIKit中有幾種接受低內(nèi)存警告的方法:

  1. applicationDidReceiveMemoryWarning:方法;
  2. 在UIViewController中重寫didReceiveMemoryWarning;
  3. 注冊(cè)接受UIApplicationDidReceiveMemoryWarningNotification通知
    如果我們對(duì)此置之不理,程序有可能直接被干掉,那時(shí)候我們就會(huì)陷入OOM的困境之中。

監(jiān)測(cè)內(nèi)存的工具

Xcode

命令行工具暫且不提,那套更加適合MacOS。
在Xcode中,我們可以使用三種工具來測(cè)量?jī)?nèi)存:

  1. Xcode memory gauge
  2. Instruments(主要是Leaks、Allocation、Counters以及System Trace中的Virtual Memory Trace)
  3. Xcode Memory Debugger
Xcode memory gauge
Instruments
Xcode Memory Debugger

在Xcode10之后,當(dāng)內(nèi)存過大的時(shí)候,也會(huì)觸發(fā)debugger,自動(dòng)捕獲 EXC_RESOURCE RESOURCE_TYPE_MEMORY異常,并自動(dòng)斷點(diǎn)在出問題的地方。

image

在在Product->Scheme->Edit Scheme->Diagnostics中,開啟 Malloc Stack 功能,建議使用Live Allocations Only選項(xiàng)。
中開啟Malloc Stack功能,使用 Live Allocations Only選項(xiàng),會(huì)在lldb中記錄調(diào)試過程中對(duì)象創(chuàng)建的堆棧,配合使用 malloc_history工具,可以方便我們定位到占用過大內(nèi)存的對(duì)象的創(chuàng)建位置。

代碼方法

獲取應(yīng)用使用真實(shí)物理內(nèi)存值的代碼:

- (NSUInteger)getResidentMemory
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
    
    int r = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)& info, & count);
    if (r == KERN_SUCCESS)
    {
        return info.resident_size;
    }
    else
    {
        return -1;
    }
}

線上內(nèi)存檢測(cè)工具

1.MLeaksFinder
2.FBRetainCycleDetector
3.OOMDetector

當(dāng)然,我們也可以自己在理解內(nèi)存檢測(cè)的原理之后,自己去實(shí)現(xiàn)一些輪子,以更加貼合自己的使用場(chǎng)景。

如何注意內(nèi)存優(yōu)化

0.多用懶加載
1.weak替代 unsafe_unretain ,以及注意assign;
2.安全的使用weak;
3.autoreleasepool多用;
4.對(duì)UI、動(dòng)畫機(jī)制深入了解,尤其是動(dòng)畫以及Cell復(fù)用機(jī)制;
5.imageName:
5.performSelect謹(jǐn)慎使用;
6.倒計(jì)時(shí)使用注意,設(shè)計(jì)一定要嚴(yán)謹(jǐn);
7.多使用Cache而非dictionary;
8.監(jiān)測(cè)性能組件使用mmap存放讀取數(shù)據(jù);
9.NSDateFormate注意;
10.謹(jǐn)慎小心的使用指針,小心野指針;
11.WKWebView 是跨進(jìn)程通信的,不會(huì)占用我們的 APP 使用的物理內(nèi)存量,但是依然要小心謹(jǐn)慎的測(cè)量;
12.在保證安全的前提下,選用一些更小的數(shù)據(jù)結(jié)構(gòu);
13.對(duì)待大的貼圖要謹(jǐn)慎使用;
14.謹(jǐn)慎小心的使用指針;
15.注意 NSDateFormatter的使用。

后續(xù)記錄計(jì)劃

SLC/MLC/TLC對(duì)比,為什么選用TLC。
OOM是個(gè)什么鬼。
如何設(shè)計(jì)一個(gè)一個(gè)內(nèi)存監(jiān)測(cè)組件。
如何注意內(nèi)存優(yōu)化中各項(xiàng)的解釋。

參考和鳴謝

《程序員的自我修養(yǎng)-鏈接、裝載和庫》第一版(第十章)
《深入理解計(jì)算機(jī)系統(tǒng)》第三版(第九章)
《iOS 和 macOS 性能優(yōu)化:Cocoa、Cocoa Touch、Objective-C 和 Swift》第一版(第五章)
《高性能iOS應(yīng)用開發(fā)》 第一版-第二章
《Effective Objective-C 2.0 編寫高質(zhì)量iOS與OS X代碼的52個(gè)有效方法》第五十條
WWDC 2018-Session 416: iOS Memory Deep Dive
iOS Memory Deep Dive
OS X Mavericks Core Technology Overview
Memory Usage Performance Guidelines
Instruments Help
iOS-Monitor-Platform
感謝傾寒、冬瓜在創(chuàng)作中給予的幫助。

結(jié)語

iOS的APM是真的難!
寫了這么多越來越覺得自己蠢?。。。。。。?br> 還是要多看書!
投簡(jiǎn)歷是真的難!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 操作系統(tǒng)對(duì)內(nèi)存的管理 沒有內(nèi)存抽象的年代 在早些的操作系統(tǒng)中,并沒有引入內(nèi)存抽象的概念。程序直接訪問和操作的都是物...
    Mr槑閱讀 16,973評(píng)論 3 24
  • 1 內(nèi)存尋址 1.1 物理地址、虛擬地址以及線性地址 物理地址: 物理內(nèi)存的內(nèi)存單元地址 虛擬地址: 程序員看到的...
    瘋狂小王子閱讀 3,131評(píng)論 3 21
  • 前言 經(jīng)典操作系統(tǒng)的虛擬內(nèi)存為什么要有虛擬內(nèi)存?尋址方式地址空間分頁缺頁處理虛擬內(nèi)存帶來的好處地址翻譯如何索引提高...
    南梔傾寒閱讀 7,032評(píng)論 11 46
  • 前言 內(nèi)存管理一向是所有操作系統(tǒng)書籍不惜筆墨重點(diǎn)討論的內(nèi)容,無論市面上或是網(wǎng)上都充斥著大量涉及內(nèi)存管理的教材和資料...
    木有sky閱讀 963評(píng)論 0 1
  • 操作系統(tǒng)概論 操作系統(tǒng)的概念 操作系統(tǒng)是指控制和管理計(jì)算機(jī)的軟硬件資源,并合理的組織調(diào)度計(jì)算機(jī)的工作和資源的分配,...
    野狗子嗷嗷嗷閱讀 12,487評(píng)論 3 34

友情鏈接更多精彩內(nèi)容