內(nèi)存管理/引用計(jì)數(shù) - alloc/retain/release/dealloc實(shí)現(xiàn)

所有內(nèi)容引用自《Objective-C 高級編程 iOS與OS X多線程和內(nèi)存管理》成艘,加入了自己的部分理解。

本節(jié)小結(jié)断箫,點(diǎn)小1跳到底部[1]
第一節(jié)瑰枫、思考方式
第三節(jié)光坝、autorelease實(shí)現(xiàn)


這里分兩種實(shí)現(xiàn)盯另,GNUstep實(shí)現(xiàn)鸳惯,蘋果的實(shí)現(xiàn)芝发。
為啥要研究GNUstep實(shí)現(xiàn)辅鲸?Cocoa不開源独悴,沒辦法知道蘋果實(shí)現(xiàn)锣尉。GNUstep開源自沧,并且是Cocoa的互換框架拇厢。


GNUstep實(shí)現(xiàn)

1旺嬉、alloc實(shí)現(xiàn)

// GNUstep/modules/core/base/Source/NSObject.m 
+ (id) alloc{
    return [self allocWithZone:NSDefaultMallocZone()];
}
+ (id)allocWithZone:(NSZone *)z{
    return NSAllocateObject (self, 0 , z);
}

struct obj_layout{
    NSUInteger retained;
};

inline id
NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone){
    int size = 計(jì)算容納對象所需的內(nèi)存大小;
    // 先分配內(nèi)存
    id  new = NSZoneMalloc(zone, size);
    // 內(nèi)存置0
    memset(new, 0, size);
    // 返回指針
    new = (id) & ((struct obj_layout *) new)[1];
}

NSZone是防止內(nèi)存碎片化引入的結(jié)構(gòu)邪媳。對內(nèi)存分配的區(qū)域進(jìn)行多重化管理,根據(jù)使用對象的目的、對象大小分配內(nèi)存雨效,提高內(nèi)存管理的效率迅涮。(就是小內(nèi)存是一段連續(xù)空間,大內(nèi)存是一段連續(xù)空間徽龟。)

因?yàn)?code>iOS運(yùn)行時系統(tǒng)的內(nèi)存管理已經(jīng)極具效率叮姑,所以目前已經(jīng)忽略了區(qū)域的概念。

alloc簡化區(qū)域后的實(shí)現(xiàn):

struct obj_layout{
    NSUInteger retained;
};

+ (id) alloc{
    int size = sizeof(struct obj_layout) + 對象大小;
    struct obj_layout *p = (struct obj_layout *) calloc(1, size);
    return (id)(p + 1);
}

其中retained保存引用計(jì)數(shù)据悔,寫入到對象頭部传透。

alloc返回的指針.png

對象引用計(jì)數(shù),可以使用retainCount獲取到极颓。實(shí)現(xiàn)如下:

- (NSUInteger)retainCount{
    return NSExtraRefCount(self) + 1;
}

inline NSUInteger
NSExtraRefCount(id anObject){
    // 由對象尋址找到對象頭部朱盐,取出retained值返回
    return ((struct obj_layout *) anObject) [-1].retained;
}

2菠隆、retain實(shí)現(xiàn)

- (id)retain{
    NSIncrementExtraRefCount(self);
    return self;
}

inline void
NSIncrementExtraRefCount(id anObject){
    // 如果超過最大值,給出提示
    if(((struct obj_layout *) anObject) [-1].retained == UNNT_MAX - 1){
      [NSException raise:NSInternalInconsistencyException format:@"NSIncrementExtraRefCount() asked to increment too far"];
  }else{ // +1
    ((struct obj_layout *) anObject) [-1].retained++;
  }
}

3、release實(shí)現(xiàn)

- (void)release{
    if (NSIncrementExtraRefCountWasZero(self)){
      [self dealloc];
  }
}

BOOL
NSIncrementExtraRefCountWasZero(id anObject){
    if (((struct obj_layout *) anObject) [-1].retained == 0){
        return YES;
    }else{
        ((struct obj_layout *) anObject) [-1].retained --;
        return NO;
    }
}

4、dealloc實(shí)現(xiàn)

- (void)dealloc{
    NSDeallocateObject(self);
}

inline void
NSDeallocateObject(id anObject){
    struct obj_layout *o = &((struct obj_layout *) anObject[-1];
    free(o);
}

小結(jié):

  • Objective-C對象中存有引用計(jì)數(shù)整數(shù)值
  • allocretain迄沫,引用計(jì)數(shù)+1
  • release引用計(jì)數(shù)-1
  • 引用計(jì)數(shù)為0時盼砍,調(diào)用dealloc廢棄對象

蘋果實(shí)現(xiàn)

NSObject源碼沒有公開睬捶,只能通過斷點(diǎn)來追蹤程序的執(zhí)行臀晃。
1座韵、alloc的實(shí)現(xiàn)

+alloc
+allocWithZone:
// 創(chuàng)建對象
class_createInstance
// 分配內(nèi)存
calloc

2宦棺、retainCount/retain/release的實(shí)現(xiàn)

// retainCount
__CFDoExternRefOperation
CFBasicHashGetCountOfKey
// retain
__CFDoExternRefOperation
CFBasicHashAddValue
// release
__CFDoExternRefOperation
CFBasicHashRemoveValue
// CFBasicHashRemoveValue返回0時蹬屹,會調(diào)用dealloc

CF前綴,是使用了Core Foundation框架。
__CFDoExternRefOperationCFRuntime.c中铡买。便于理解,簡化實(shí)現(xiàn)如下景埃。

int __CFDoExternRefOperation(uintptr_t op,id obj){
    CFBasicHashRef table =  取得對象對應(yīng)的哈希表(obj);
    int count;

    switch(op){
        case  OPERATION_retainCount:
              count = CFBasicHashGetCountOfKey(table, obj);
              return count;

        case  OPERATION_retain:
              CFBasicHashAddValue(table,obj);

        case  OPERATION_release:
              count = CFBasicHashRemoveValue(table,obj);
              return 0 == count;
    }
}

大致可以得出完慧,采用的是哈希表來管理引用計(jì)數(shù)的蛤织,表健值是內(nèi)存塊地址乞巧。
前面GNUstep實(shí)現(xiàn),是把引用計(jì)數(shù)放在對象內(nèi)存塊頭部。和蘋果相比各自的好處:

???
放在頭部的好處:

  • 節(jié)約代碼量旁蔼。少量代碼就可以實(shí)現(xiàn)
  • 能統(tǒng)一管理引用計(jì)數(shù)內(nèi)存塊和對象內(nèi)存塊贞谓。

?????
使用哈希表作為引用計(jì)數(shù)表的好處:

  • 對象內(nèi)存塊分配不再考慮內(nèi)存塊頭部。
  • 哈希表存有內(nèi)存塊地址,可以追溯到各個對象的內(nèi)存塊广辰。

第二點(diǎn)特別重要,即使內(nèi)存塊損壞了,只要引用計(jì)數(shù)表沒有破壞囱持,就可以確認(rèn)內(nèi)存塊的位置晴弃。特別是檢測內(nèi)存泄露時,可以幫助定位各對象是否持有世曾。


小結(jié)

1蕊程、可以通過GNUstep源碼來推測蘋果實(shí)現(xiàn)。
2、alloc\retain 引用計(jì)數(shù)+1。
3、release引用計(jì)數(shù)-1,為0時,調(diào)用dealloc廢棄對象风喇。
4豁鲤、引用計(jì)數(shù)由哈希表管理,方便追溯內(nèi)存塊,定位內(nèi)存泄露。


  1. ??假裝是錨點(diǎn)的腳注 ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子霜瘪,更是在濱河造成了極大的恐慌布讹,老刑警劉巖膘流,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡唱矛,警方通過查閱死者的電腦和手機(jī)渐北,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門歧蒋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來序臂,“玉大人,你說我怎么就攤上這事〈踵冢” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我认境,道長鉴未,這世上最難降的妖魔是什么连茧? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任厌衙,我火速辦了婚禮拐揭,結(jié)果婚禮上堂污,老公的妹妹穿的比我還像新娘。我一直安慰自己式镐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布尸昧。 她就那樣靜靜地躺著,像睡著了一般茫负。 火紅的嫁衣襯著肌膚如雪无虚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天戚哎,我揣著相機(jī)與錄音往弓,去河邊找鬼疏唾。 笑死,一個胖子當(dāng)著我的面吹牛亮航,可吹牛的內(nèi)容都是我干的荸实。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼缴淋,長吁一口氣:“原來是場噩夢啊……” “哼准给!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起重抖,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤露氮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后钟沛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體畔规,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年恨统,在試婚紗的時候發(fā)現(xiàn)自己被綠了叁扫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡畜埋,死狀恐怖莫绣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悠鞍,我是刑警寧澤对室,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站咖祭,受9級特大地震影響掩宜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜么翰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一牺汤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浩嫌,春花似錦檐迟、人聲如沸戴已。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽糖儡。三九已至,卻和暖如春怔匣,著一層夾襖步出監(jiān)牢的瞬間握联,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工每瞒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留金闽,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓剿骨,卻偏偏與公主長得像代芜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浓利,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

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