Block技術在iOS開發中很是流行也很方便,可是稍微疏忽就可能會產生引用沒法被釋放的問題,從而形成內存泄漏。那如何知道哪一個Block持有了對象並形成內存泄漏呢?bash
一個解決的方法是在程序運行時經過Xcode的Debug Memory Graph 來查看當前進程中全部生命週期內的對象。這樣能夠在調試時經過這個功能發現一些原本應該被釋放可是卻沒有被釋放的對象。從而肯定哪些對象有內存泄漏的嫌疑。 函數
當點擊某個對象時,右邊能夠看出這個對象的內存分配狀況以及被引用的狀況,從而能夠進一步跟蹤確認出對象是被誰持有和引用而沒有被正常的釋放。spa
在上圖中黑色的線部分就是對象被強引用的序列圖。調試
回到主題,你能夠上面的圖形中看出對象ViewController2是被一個**__NSMallocBlock__** 所持有了,可是你只能看到這個Block對象的內存地址(右上角)而已。要想看這個Block所對應的實現代碼時你只須要在lldb控制檯輸入以下信息:code
(lldb) dis -s *(void**)(0x600002f51110+16)
MyLoadTest`__27-[ViewController2 loadView]_block_invoke:
0x10c79c080 <+0>: pushq %rbp
0x10c79c081 <+1>: movq %rsp, %rbp
0x10c79c084 <+4>: subq $0x40, %rsp
0x10c79c088 <+8>: movq %rdi, -0x8(%rbp)
0x10c79c08c <+12>: movq %rdi, %rax
0x10c79c08f <+15>: movq $0x0, -0x10(%rbp)
0x10c79c097 <+23>: leaq -0x10(%rbp), %rcx
0x10c79c09b <+27>: movq %rdi, -0x20(%rbp)
複製代碼
上述指令中 dis -s 地址 的做用是用來反彙編某個地址所對應符號信息以及開始一部分的彙編實現。cdn
命令中然後面的0x600002f51110 則是Block對象的地址,這裏加16的意思是由於Block對象的內部偏移16個字節的位置就是Block對象所保存的執行代碼的函數地址。 因此經過這個指令就能夠輕鬆的知道是哪一個Block對象強持有了對象而不會被釋放了。對象
從上面的第一張圖中的源代碼能夠看出Block內部持有了self對象致使了對象沒法被正常釋放。blog
經過上述的命令能夠在調試時用在任何地方來查看某個Block的函數信息。生命週期
這裏須要注意的是當你在一個方法內定義了多個Block時。這些Block的函數符號的規則是:進程
-[block定義所在的方法名]_block_invoke.序號
複製代碼
在方法中定義的第一個block是沒有序號,然後續的則根據定義的數量從2遞增。
好比下面類中的定義的四個block:
@interface CA
-(void)foo1{
void(^b)(void) =^{};
void(^b)(void) =^{};
}
-(void)foo2{
void(^b)(void) =^{};
void(^b)(void) =^{};
}
@end
複製代碼
所對應的block的符號是:
-[CA foo1]_block_invoke
-[CA foo1]_block_invoke.2
-[CA foo2]_block_invoke
-[CA foo2]_block_invoke.2
複製代碼