一、什么是棧對(duì)象和堆對(duì)象
在Objective-C中,對(duì)象通常是指一塊有特定布局的連續(xù)內(nèi)存區(qū)域。我們通常這樣創(chuàng)建一個(gè)對(duì)象
NSObject *obj = [[NSObject alloc] init];
這行代碼創(chuàng)建了一個(gè)NSObject類型的指針obj和一個(gè)NSObject類型的對(duì)象,obj指針存儲(chǔ)在棧上,而其指向的對(duì)象則存儲(chǔ)在堆上(堆對(duì)象)
目前OC并不支持直接在棧上創(chuàng)建對(duì)象(棧對(duì)象),但可以通過(guò)如下方式間接的創(chuàng)建
struct {
Class isa;
} fakeNSObject;
fakeNSObject.isa = [NSObject class];
NSObject *obj = (NSObject *)&fakeNSObject;
NSLog(@"%@", [obj description]);
二、棧對(duì)象優(yōu)缺點(diǎn)
1、優(yōu)點(diǎn)
- 速度
在棧上創(chuàng)建對(duì)象是非??斓?,因?yàn)楹芏鄸|西在編譯時(shí)就確定了,運(yùn)行時(shí)分配空間幾乎不耗時(shí);相對(duì)而言在堆上創(chuàng)建對(duì)象就非常耗時(shí)。 - 簡(jiǎn)單
站對(duì)象的生命周期是確定的,對(duì)象出棧以后就會(huì)被釋放,不會(huì)存在內(nèi)存泄漏,但這同樣也是棧對(duì)象的最大缺點(diǎn)。
2、缺點(diǎn)
- 生命周期固定
OC變量有效范圍是由“{}”包含的塊來(lái)決定的,也就是說(shuō)找對(duì)象的生命周期僅限于其所在的塊里,出了塊立馬會(huì)被釋放,一個(gè)對(duì)象被創(chuàng)建以后有可能會(huì)通過(guò)方法調(diào)用傳遞到別的方法,當(dāng)找對(duì)象的創(chuàng)建方法返回時(shí),棧對(duì)象會(huì)被一起pop出棧而釋放,導(dǎo)致其沒(méi)法在別處被繼續(xù)持有。此時(shí)retain操作會(huì)失效,除非用copy方法在想持有該棧對(duì)象的地方重新拷貝一份屬于自己的站對(duì)象。
因此,棧對(duì)象會(huì)給對(duì)象的內(nèi)存管理造成巨大的麻煩。 - 空間
現(xiàn)在操作系統(tǒng)的棧和線程綁定,而??臻g是有限的,具體如下:
512 KB (secondary threads)
8 MB (OS X main thread)
1 MB (iOS main thread)
因此對(duì)象如果都在棧上創(chuàng)建不太現(xiàn)實(shí),而堆只要物理內(nèi)存不警告可以無(wú)限使用。
綜合以上優(yōu)缺點(diǎn),OC選擇用堆存儲(chǔ)對(duì)象。
三、真的沒(méi)有對(duì)象嗎
實(shí)際上OC里的block卻是棧對(duì)象,因此棧對(duì)象面臨的問(wèn)題在block身上一個(gè)都不少,但由于block是僅有的特殊對(duì)象,大家對(duì)他的特殊性都已經(jīng)習(xí)慣了。
另外,根據(jù)前面所說(shuō),棧對(duì)象的有效區(qū)域僅限于其所在的塊,因此像下面的代碼就無(wú)法輸出期望的結(jié)果:
void (^block)();
if(x)
{
block = ^{ printf("x\n"); };
}
else
{
block = ^{ printf("not x\n"); };
}
block();