引入
創建對象LGPerson類,在ViewDidLoad中進行如下編碼
<LGPerson: 0x6000006543c0> - 0x6000006543c0 - 0x7ffee47290e8
<LGPerson: 0x6000006543c0> - 0x6000006543c0 - 0x7ffee47290e0
<LGPerson: 0x6000006543c0> - 0x6000006543c0 - 0x7ffee47290d8
*/
LGPerson *p1 = [LGPerson alloc];
LGPerson *p2 = [p1 init];
LGPerson *p3 = [p1 init];
LGNSLog(@"%@ - %p - %p",p1,p1,&p1);
LGNSLog(@"%@ - %p - %p",p2,p2,&p2);
LGNSLog(@"%@ - %p - %p",p3,p3,&p3);
從調試終端答應的結果可知:存儲p1,p2,p3的地址是不一樣的,但p1,p2,p3指向同一內存空間,棧內存連續,p1,p2,p3的地址相差8個字節(64位系統,指針存儲需要8個字節)
思考: 對象的alloc底層究竟做了什么?
底層原理探索的三種方式
方法一 下符號斷點的形式直接跟流程
- 添加符號斷點alloc
- LGPerson *p1 = [LGPerson alloc];前添加普通斷點
- 運行代碼,首先會被alloc斷點斷住,這是由于系統做了許多對象的內存分配,將alloc斷點設置不進入,再全速運行,直到LGPerson *p1 = [LGPerson alloc];處斷點斷住,再打開alloc的斷點,再全速運行
- 進入[LGPerson alloc]的alloc斷點,發現由于LGPerson沒有實現alloc方法,是父類的alloc方法,[NSObject alloc]
image
- 單步執行,step into, 進入_objc_rootAlloc
image
方法二 通過摁住control - step into
image
- 符號斷點objc_alloc,查看源碼出處
- 單步執行,step into, 進入_objc_rootAlloc
方法三 匯編查看跟流程
-
設置 Debug -> Debug Workflow -> Always Show Disassembly
image control+step into 進入到objc_alloc
設置符號斷點objc_alloc,查看源碼出處
單步執行,step into, 進入_objc_rootAlloc
在obj781源碼工程中查看alloc源碼
蘋果開源源碼
https://opensource.apple.com
https://opensource.apple.com/tarballs
找到Source下得NSObject.mm中+ (id)alloc的實現
image
設置編譯器優化
image
對象內存分配的字節對齊
iOS使用16字節對齊內存分配方式,對象分配內存時需要分配地址的有:isa,對象的屬性,將實際需要的地址傳入函數align16,進行16字節的對齊返回
static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}
init & new
init
return (id)obj
是構造方法,工廠設計模式,為開發者提供初始化入口
new
[callAlloc(self, false/checkNil/) init]
相當于 alloc+init,但不推薦用new,如果對象子定義了初始化函數initWithxxx,則不會調用重寫的initWithxxx:的初始化
對象地址的分配和屬性地址
mask
image
對象的isa 和屬性的地址
image