High Performance iOS Apps - Autorelease Pool Blocks

High Performance iOS Apps - Autorelease Pool Blocks 筆記。改寫為 Swift 版本。附加一個(gè) Instrument 測(cè)試。

嵌套的 autoreleasepool

所有 autorelease 中的對(duì)象都會(huì)收到一個(gè) autorelease 的消息,在這個(gè) autorelease block 結(jié)束之后,它們都會(huì)收到 release 通知。

autoreleasepool { () -> () in
    //some code
    autoreleasepool(invoking: { () -> () in
        //some more code
    })
}

在同一個(gè)方法中嵌套 autoreleasepool 不是一個(gè)常見的用法。當(dāng)一個(gè)方法傳遞到另一個(gè)方法,被呼叫的方法可以有自己的 autoreleasepool 以便提早釋放對(duì)象。

什么情況下使用?

  1. 在循環(huán)中創(chuàng)建很多臨時(shí)對(duì)象的時(shí)候
  2. 自己創(chuàng)建線程的時(shí)候

在循環(huán)中釋放

在循環(huán)內(nèi)部創(chuàng)建 autoreleasepool,這樣可以在每次循環(huán)結(jié)束后釋放掉內(nèi)存,而不是等到所有循環(huán)都結(jié)束了才釋放,大幅降低最大內(nèi)存使用量。

for i in 0..<userCount{
    autoreleasepool(invoking: { () -> () in
        let p = userDatabase.userAtIndex(i: i) as Person
        
        let fname = p.fname == nil ? p.fname : askUserForFirstName()
        let lname = p.lname == nil ? p.lname : askUserForLastName()
        
        p.fname = fname
        p.lname = lname
        
        userDatabase.updateUser(p: p)
    })
}

在自定義的線程中釋放

每個(gè)線程都有自己的 autoreleasepool block 棧。對(duì)于自定義的線程,你必須創(chuàng)建自己的 autoreleasepool。

func myThreadStart(sender: Any){
        autoreleasepool {
            
        }
    }

在別的地方

let myThread = Thread(target: self, selector: #selector(myThreadStart), object: nil)
myThread.start()

測(cè)試

運(yùn)行一段消耗內(nèi)存的程序

for _ in 0 ..< 5 {
    autoreleasepool {
        for _ in 0 ..< 1000 {
            let imagex = UIImage(named: "image")
            print("\(String(describing: imagex?.description))")
        }
    }
}

菜單 Product > Profile 調(diào)出 Instrument,選擇 Allocations。點(diǎn)錄制執(zhí)行,然后停止。option + 中鍵放大時(shí)間軸??梢钥吹?5 個(gè)內(nèi)存占用的波形,峰值是 3.29M。每次外部循環(huán)釋放一次內(nèi)存。

autoreleasepool1.png

修改程序?yàn)檠h(huán)結(jié)束后釋放:

autoreleasepool {
for _ in 0 ..< 5 {
    for _ in 0 ..< 1000 {
        let imagex = UIImage(named: "image")
        print("\(String(describing: imagex?.description))")
    }
}
}

內(nèi)存占用一直攀升,釋放前到達(dá)峰值 10.90M。

autoreleasepool2.png

Statistics 列表中找到占用內(nèi)存較多的一行,點(diǎn)擊右側(cè)箭頭進(jìn)入 Heap & Anonymous VM 列表,選擇產(chǎn)生內(nèi)存占用的條目,右側(cè) Stack Trace 中可以看到棧的最頂端是哪個(gè)類的哪個(gè)方法產(chǎn)生了這部分內(nèi)存。

autoreleasepool3.png

Stack Trace 中雙擊某一行會(huì)進(jìn)入具體代碼中的位置。

參考:StackoverFlow

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容