一橄务、關(guān)于引用計(jì)數(shù):
讀了《Objective-C高級(jí)編程(iOS與OS X多線(xiàn)程和內(nèi)存管理)》蜂挪,發(fā)現(xiàn)吊炸天的感覺(jué)棠涮,所以記錄下严肪。嗯 還是自己太菜了驳糯,好像是7年前的書(shū)了。 自己盡然沒(méi)有去認(rèn)真的去研讀隧枫,慚愧官脓,慚愧卑笨!
- ARC之前引用計(jì)數(shù)是得程序員自己管理的赤兴,ARC之后是編譯器幫我們管理的桶良。但是 是不是就不用了解呢陨帆?如果你還在用OC的話(huà)絕對(duì)用處很大疲牵,農(nóng)村人纲爸,不講套路读虏。
- 引用計(jì)數(shù),引用書(shū)中的例子:
最早進(jìn)入辦公室的人開(kāi)燈 ->最后離開(kāi)辦公室的人關(guān)燈
中間進(jìn)入就是++题翻,離開(kāi)--
- 管理方式:
1.自己生成的對(duì)象嵌赠,自己持有
2.非自己生成的對(duì)象姜挺,自己也能持有
3.不需要自己持有持有的對(duì)象時(shí)釋放
4.非自己持有的對(duì)象無(wú)法釋放
以上就是對(duì)引用計(jì)數(shù)的概括,有點(diǎn)枯燥词渤,但是把內(nèi)存管理讀完再來(lái)看缺虐,就非常美妙高氮。
二剪芍、alloc/retain/release/dealloc實(shí)現(xiàn)
-
必須先搞定這幾個(gè)鬼東西窖铡,這幾個(gè)可是OC內(nèi)存管理的基石费彼,按照慣例箍铲,思維導(dǎo)圖 懟一發(fā):
圖片.png - 密密麻麻小染,看著是不是很反感裤翩。跟著走進(jìn)去你會(huì)發(fā)現(xiàn)花姑娘
因?yàn)镹SObject不開(kāi)源踊赠,所以這個(gè)GNUstep現(xiàn)在是2.7.0版本今穿。這個(gè)鬼基本由于NSObject內(nèi)部實(shí)現(xiàn)方法一樣,查不了多少拔创,還有一個(gè)runtime的源代碼也準(zhǔn)備好 開(kāi)搞
1.alloc方法的實(shí)現(xiàn)
-在base/Source/Foundation/NSObject.m的+ (id) alloc方法里,最后調(diào)用
NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone)
// 簡(jiǎn)化后主要代碼
// size:計(jì)算容納對(duì)象所需內(nèi)存的大小
//obj_layout:保存著引用計(jì)數(shù)retained
// 蘋(píng)果用哈希表實(shí)現(xiàn) GNUstep用占用頭部?jī)?nèi)存實(shí)現(xiàn)
int size = class_getInstanceSize(aClass) + extraBytes + sizeof(struct obj_layout);
if (zone == 0)
{
// NSZone是為防止內(nèi)存碎片化引入的結(jié)構(gòu)侣滩,對(duì)內(nèi)存分配區(qū)域進(jìn)行多重化管理
// 根據(jù)對(duì)象的目的君珠、大小、分配
zone = NSDefaultMallocZone();
}
// 給對(duì)象分配內(nèi)存空間
new = NSZoneMalloc(zone, size);
if (new != nil)
{
// 將內(nèi)存空間置為0
memset (new, 0, size);
new = (id)&((obj)new)[1];
object_setClass(new, aClass);
AADD(aClass, new);
}
// 返回對(duì)象指針
return new;
2.retain方法的實(shí)現(xiàn)
- 在base/Source/Foundation/NSObject.m的- (id) retain方法里,最后調(diào)用
static id retain_fast(id anObject)
1.weak修飾的時(shí)候返回本身不做處理
2.static id objc_retain_fast_np_internal(id anObject)主要的就是 ((obj)anObject)[-1].retained++;
3.這里說(shuō)明一下 ((obj)anObject)[-1]GNUstep用占用頭部?jī)?nèi)存實(shí)現(xiàn),就是obj返回的指針-1就是指向retained的內(nèi)存地址,蘋(píng)果用哈希表實(shí)現(xiàn)會(huì)有點(diǎn)不同
3.release方法的實(shí)現(xiàn)
-在base/Source/Foundation/NSObject.m的- (oneway void) release方法里产上,最后調(diào)用
static void release_fast(id anObject)
1.weak修飾的時(shí)候返回本身不做處理
2.引用計(jì)數(shù)--((obj)anObject)[-1].retained--
3.引用計(jì)數(shù)為0時(shí)調(diào)用dealloc方法
4.dealloc方法的實(shí)現(xiàn)
-在base/Source/Foundation/NSObject.m的- (void) dealloc方法里
NSDeallocateObject(id anObject)
// 簡(jiǎn)化后代碼
NSDeallocateObject(id anObject)
{
// 獲取類(lèi)對(duì)象
Class aClass = object_getClass(anObject);
// 判斷 當(dāng)前類(lèi)對(duì)象 元類(lèi)對(duì)象不為空
if ((anObject != nil) && !class_isMetaClass(aClass))
{
//ARC下
obj o = &((obj)anObject)[-1]; // 獲取對(duì)象指針
NSZone *z = NSZoneFromPointer(o); // tagePoint尋址
if (NSZombieEnabled == YES)
{
// 如果僵尸對(duì)象散列表不為空 放進(jìn)僵尸對(duì)象散列表
if (0 != zombieMap)
{
pthread_mutex_lock(&allocationLock);
NSMapInsert(zombieMap, (void*)anObject, (void*)aClass);
pthread_mutex_unlock(&allocationLock);
}
// 釋放僵尸對(duì)象 或者 添加僵尸對(duì)象
if (NSDeallocateZombies == YES)
{
object_dispose(anObject);
}
else
{
object_setClass(anObject, zombieClass);
}
}
else
{
object_dispose(anObject);
}
}
return;
}
- 上面注釋寫(xiě)的很清楚了姻僧,我主要把非ARC下的代碼刪了赌莺,retain和release主要的說(shuō)清楚挎扰,其他的大家可以自己看看遵倦,然后發(fā)現(xiàn)object_dispose()方法沒(méi)有了,不急因?yàn)閛bject_dispose()是runtime的東西
- 在runtime源碼objc/Source/objc-runtime-new.mm里面的
id object_dispose(id obj)
- 釋放之前還調(diào)用了objc_destructInstance(obj)方法
void *objc_destructInstance(id obj)
{
if (obj) {
// Read all of the flags at once for performance.
// 判斷是否有C++析構(gòu)函數(shù)
bool cxx = obj->hasCxxDtor();
// 是否有關(guān)聯(lián)對(duì)象
bool assoc = obj->hasAssociatedObjects();
// This order is important.
// 清除有C++析構(gòu)函數(shù)
if (cxx) object_cxxDestruct(obj);
// 清除關(guān)聯(lián)對(duì)象表 AssociationsManager對(duì)應(yīng)的value
if (assoc) _object_remove_assocations(obj);
obj->clearDeallocating();
}
return obj;
}
-
最后調(diào)用了obj->clearDeallocating()可以自己進(jìn)去看看,思維導(dǎo)圖里面注釋的比較清楚如圖:
圖片.png - 至于從何得知void *objc_destructInstance(id obj) 的方法
// 判斷是否有C++析構(gòu)函數(shù)
bool cxx = obj->hasCxxDtor();
// 是否有關(guān)聯(lián)對(duì)象
bool assoc = obj->hasAssociatedObjects();
- 可以根據(jù)isa指針聯(lián)合體里面有記錄的禁舷,大致如下:
union isa_t
struct {
// 1代表優(yōu)化后的使用位域存儲(chǔ)更多的信息派近。
uintptr_t nonpointer : 1;
// 是否有設(shè)置過(guò)關(guān)聯(lián)對(duì)象
uintptr_t has_assoc : 1;
// 是否有C++析構(gòu)函數(shù)
uintptr_t has_cxx_dtor : 1;
// 存儲(chǔ)著Class對(duì)象的內(nèi)存地址信息
uintptr_t shiftcls : 33;
// 用于在調(diào)試時(shí)分辨對(duì)象是否未完成初始化
uintptr_t magic : 6;
// 是否有被弱引用指向過(guò)战坤。
uintptr_t weakly_referenced : 1;
// 對(duì)象是否正在釋放
uintptr_t deallocating : 1;
// 引用計(jì)數(shù)器是否過(guò)大無(wú)法存儲(chǔ)在isa中
// 如果為1碟嘴,那么引用計(jì)數(shù)會(huì)存儲(chǔ)在一個(gè)叫SideTable的類(lèi)的屬性中
uintptr_t has_sidetable_rc : 1;
// 里面存儲(chǔ)的值是引用計(jì)數(shù)器減1
uintptr_t extra_rc : 19;
};
- 今天就到這了栅组,小子頭昏眼花刃麸,急需按一波。陸續(xù)會(huì)更新內(nèi)存管理的內(nèi)容,各位看官,回見(jiàn)