OC - OC的內(nèi)存管理機制

導(dǎo)讀

  • 一、為什么要進行內(nèi)存管理
  • 二拟赊、內(nèi)存管理機制
  • 三痛垛、內(nèi)存管理原則
  • 四草慧、MRC手動內(nèi)存管理
  • 五、ARC自動內(nèi)存管理
  • 六匙头、Autorelease自動釋放池
  • 參考:http://www.reibang.com/p/7903c8283e26

一漫谷、 為什么要進行內(nèi)存管理

  1. 移動設(shè)備分配給每個App的內(nèi)存有限,App運行中會創(chuàng)建大量對象蹂析, OC對象存儲在堆中舔示,系統(tǒng)不會自動釋放堆中的內(nèi)存,對象沒有及時釋放电抚,就會占用大量內(nèi)存惕稻,系統(tǒng)會發(fā)出內(nèi)存警告,對應(yīng)用運行造成影響蝙叛。
  • 相關(guān)概念:
    內(nèi)存泄露:代碼塊結(jié)束時其內(nèi)部的所有局部變量會被回收俺祠,指向?qū)ο蟮闹羔樢脖换厥眨绻麑ο鬀]有指針指向,但依然存在于內(nèi)存中蜘渣,造成內(nèi)存泄露淌铐。
    野指針錯誤:訪問了一塊壞的內(nèi)存(已經(jīng)被回收的,不可用的內(nèi)存)蔫缸。
    僵尸對象:所占內(nèi)存已經(jīng)被回收的對象腿准,僵尸對象不能再被使用。(打開僵尸對象檢測)
    空指針:沒有指向任何東西的指針(存儲的東西是0捂龄、null释涛、 nil),給空指針發(fā)送消息不會報錯倦沧。

二唇撬、內(nèi)存管理機制

  1. 在C#中都有GC在自動管理內(nèi)存,但是在OC中沒有垃圾回收機制展融,OC提供了一套機制來管理內(nèi)存窖认,即“引用計數(shù)”(retain counting):
  • 每一個對象都有一個引用計數(shù)(retain count),對象被創(chuàng)建的時候告希,引用計數(shù)的值是1 當(dāng)調(diào)用對象的alloc扑浸、retain、new燕偶、copy方法之后引用計數(shù)器值自動在原來的基礎(chǔ)上加1喝噪,當(dāng)調(diào)用對象的release方法之后引用計數(shù)器值減1,調(diào)用autorelease 使對象的引用計數(shù)在未來的某個時候減1指么, 當(dāng)引用計數(shù)值是0的時候酝惧,對象將被銷毀。
  • 在每個OC對象內(nèi)部伯诬,都專門有4個字節(jié)的存儲空間來存儲引用計數(shù)器晚唇。
內(nèi)存管理范圍:任何繼承NSObject的對象;OC中的基本類型存儲在棧上盗似,由系統(tǒng)進行管理哩陕。 
內(nèi)存管理方法有:MRC(手動引用計數(shù))、ARC(自動引用計數(shù))赫舒、Autorelease(自動釋放池)悍及。

三、內(nèi)存管理原則

  1. 誰創(chuàng)建接癌, 誰release心赶。
    如果你通過alloc、new扔涧、copy來創(chuàng)建了一個對象,那么你就必須調(diào)用release或者autorelease方法。不是你創(chuàng)建的就不用你去負(fù)責(zé)枯夜。
  2. 誰retain弯汰, 誰release。
    只要你調(diào)用了retain湖雹,無論這個對象時如何生成的咏闪,你都要調(diào)用release。
  3. 除了alloc摔吏、new或copy之外的方法創(chuàng)建的對象在內(nèi)部都被聲明了autorelease鸽嫂,如[UIButton buttonWithType:]
  4. 在一定的代碼段內(nèi),對同一個對象所做的copy征讲、alloc和retain的操作次數(shù)應(yīng)當(dāng)與release和 autorelease操作的次數(shù)相等据某。
    Apple官網(wǎng)內(nèi)存管理三定律
    1. 一個對象可以有一個或多個擁有者
    2. 當(dāng)對象一個擁有者都沒有時,就會被回收
    3. 一個對象如果想保留不被回收,必須具有擁有者

四、MRC手動引用計數(shù)

  • 在引入ARC(Automatic Reference Counting)自動引用計數(shù)機制之前诗箍,OC的內(nèi)存管理需要由開發(fā)人員手動維護即MRC癣籽。
  • 在Xcode4.2之后的版本中??引入了ARC,程序編譯時滤祖,Xcode可以自動為你的代碼添加內(nèi)存釋放代碼筷狼,如果編寫手動釋放代碼Xcode會報錯,因此如果使用的Xcode4.2之后的版本匠童,必須手動關(guān)閉ARC埂材,這樣才有助于我們理解OC的內(nèi)存管理機制。
  • 為了理解OC的內(nèi)存管理機制汤求,需要在Xcode中關(guān)閉ARC:項目屬性—Build Settings--搜索“garbage”找到Objective-C Automatic Reference Counting設(shè)置為No即可俏险。


(一) Set方法的代碼規(guī)范
  1. 基本數(shù)據(jù)類型:直接復(fù)制
    -(void)setAge:(int)age
    {
    _age=age;
    }
  2. OC對象類型
    -(void)setCar:(Car *)car
    {
    //先判斷是不是新傳進來的對象
    If(car!=_car)
    {
    //對舊對象做一次release
    [_car release];//若沒有舊對象,則沒有影響
    //對新對象做一次retain
    _car=[car retain];
    }
    }
(二) dealloc方法的代碼規(guī)范
  1. 一定要[super dealloc]首昔,而且要放到最后
  2. 對self(當(dāng)前)所擁有的的其他對象做一次release操作
    -(void)dealloc
    {
    [_car release];
    [super dealloc];
    }
(三) 實例代碼規(guī)范
  1. WZKPerson.h
#import <Foundation/Foundation.h>
@interface WZKPerson : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)NSInteger age;
@end
  • WZKPerson.m
    #import "WZKPerson.h"
    @implementation WZKPerson
    -(void)dealloc
    {
    self.name=nil;
    /*最后一定要調(diào)用父類的dealloc方法寡喝;
    目的:一是父類可能有其他引用對象需要釋放;二是當(dāng)前對象真正的釋放操作是在super的dealloc中完成的勒奇;
    */
    [super dealloc];
    }
    @end

  • main.m(部分代碼)
    //調(diào)用alloc预鬓,引用計數(shù)+1
    WZKPerson *personTest=[[WZKPerson alloc] init];
    personTest.name=@"test";
    personTest.age=30;

    //輸出personTest對象的引用計數(shù)
    NSLog(@"personTest的引用計數(shù):%lu",[personTest retainCount]);
    //輸出結(jié)果:personTest的引用計數(shù):1
    
    //執(zhí)行personTest的dealloc方法
    //調(diào)用過release方法之后,personTest指向的對象就會被銷毀赊颠,但是此時變量personTest中還存放著WZKPerson對象的地址
    [personTest release];
    
    //如果不設(shè)置personTest=nil格二,則personTest就是一個野指針,它指向的內(nèi)存不屬于這個程序竣蹦,非常危險
    personTest=nil;
    
    //如果不設(shè)置personTest=nil顶猜,此時再調(diào)用personTest的release方法會報錯
    //如果設(shè)置了personTest=nil,此時personTest已經(jīng)是空指針了痘括,則oc中給空指針發(fā)送消息是不會報錯的
    [personTest release];
    
    WZKPerson *personTest2=[[WZKPerson alloc] init];
    personTest2.name=@"test2";
    personTest2.age=30;
    
    //輸出結(jié)果:personTest的引用計數(shù):1
    NSLog(@"personTest2的引用計數(shù):%lu",[personTest2 retainCount]);
    
    //引用計數(shù)+1
    [personTest2 retain];
    //輸出結(jié)果:personTest的引用計數(shù):2
    NSLog(@"personTest2的引用計數(shù):%lu",[personTest2 retainCount]);
    
    //引用計數(shù)-1
    [personTest2 release];
    //輸出結(jié)果:personTest的引用計數(shù):1
    NSLog(@"personTest2的引用計數(shù):%lu",[personTest2 retainCount]);
    
    //執(zhí)行personTest2的dealloc方法
    [personTest2 release];
    
    personTest2=nil;
    
  • 在上述代碼中长窄,可以通過dealloc方法來查看是否一個對象已經(jīng)被回收滔吠,如果沒有回收,則有可能造成內(nèi)存泄漏挠日。
    如果一個對象被釋放后疮绷,那么最后引用它的變量需要手動設(shè)置為nil,否則可能造成野指針錯誤嚣潜。

五冬骚、ARC內(nèi)存管理機制

(一) ARC的判斷準(zhǔn)則
  • 只要沒有強指針指向,對象就會被釋放懂算。
(二) 指針分類
  • 強指針:默認(rèn)的情況下只冻,所有的指針都是強指針,關(guān)鍵字strong
  • 弱指針:_ _weak關(guān)鍵字修飾的指針
  1. 聲明一個弱指針如下:
    _ _weak Person *p;
    //ARC中计技,只要弱指針指向的對象不在了喜德,就直接把弱指針做清空操作。
    _ _weak Person *p=[[Person alloc] init];
    //不合理酸役,對象一創(chuàng)建出來就被釋放掉住诸,對象釋放掉后,ARC把指針自動清零涣澡。
  2. ARC中在property處不再使用retain贱呐,而是使用strong,在dealloc中不需要再[super dealloc]
    @property(nonatomic,strong)Dog *dog;
    // 意味著生成的成員變量dog是一個強指針入桂,相當(dāng)于以前的retain奄薇。
    //如果換成是弱指針,則換成weak抗愁,不需要加
    _馁蒂。
(三) ARC的特點總結(jié)
  1. 不允許調(diào)用release、retain蜘腌、retainCount
  • 允許重寫dealloc沫屡,但是不允許調(diào)用[super dealloc]
  • @property的參數(shù):
 Strong:相當(dāng)于原來的retain(適用于OC對象類型),成員變量是強指針
Weak:相當(dāng)于原來的assign(適用于oc對象類型)撮珠,成員變量是弱指針
Assign:適用于非OC對象類型(基礎(chǔ)類型)
(四) 補充
  1. 讓程序兼容ARC和非ARC部分沮脖。轉(zhuǎn)變?yōu)榉茿RC -fno-objc-arc 轉(zhuǎn)變?yōu)锳RC的, -f-objc-arc 芯急。
  • ARC也需要考慮循環(huán)引用問題:一端使用retain勺届,另一端使用assign。


  • 提示:字符串是特殊的對象娶耍,但不需要使用release手動釋放免姿,這種字符串對象默認(rèn)就是autorelease的,不用額外的去管內(nèi)存榕酒。

六胚膊、 Autorelease自動釋放池

  • 在OC中存在著一種內(nèi)存自動釋放機制叫做自動釋放池(或自動引用計數(shù))故俐,但是與C#不同的是,這僅僅是一種半自動的機制紊婉,有些操作還是需要進行手動設(shè)置购披。
(一) 下面通過代碼來了解一下自動釋放池
  1. WZKPerson.h
    //構(gòu)造函數(shù)
    -(WZKPerson *)initWithName:(NSString *)name age:(NSInteger)age;
    //獲取對象的類方法
    +(WZKPerson *)personWithName:(NSString *)name;
  • WZKPerson.m
    -(WZKPerson *)initWithName:(NSString *)name age:(NSInteger)age
    {
    self=[super init];
    if (self) {
    _name=[name copy];
    _age=age;
    }
    return self;
    }

    +(WZKPerson *)personWithName:(NSString *)name
    {
        //這里調(diào)用了autorelease
        //OC類庫中的類方法一般都不需要手動釋放,內(nèi)部已經(jīng)調(diào)用了autorelease方法肩榕;
        WZKPerson *person=[[[WZKPerson alloc] init] autorelease];
        return person;
    }
    
  • main.m(部分代碼)
    int main(int argc, const char * argv[]) {
    @autoreleasepool {
    WZKPerson *person1=[[WZKPerson alloc] init];
    //調(diào)用autorelease方法,后面就不需要手動調(diào)用release方法了
    [person1 autorelease];
    //由于autorelease是延遲釋放(延遲到自動釋放池銷毀)惩妇,

      //所以這里仍然可以使用person1對象
      person1.name=@"Kevin";
    
      //調(diào)用autorelease方法
      WZKPerson *person2=[[[WZKPerson alloc] initWithName:@"Kevin" age:27] autorelease];
    
      //內(nèi)部已經(jīng)調(diào)用了autorelease株汉,所以不需要手動釋放
      //另外由于內(nèi)存管理原則,在外部不使用alloc歌殃、new乔妈、copy操作,
      //就不需要調(diào)用release或autorelease氓皱,所以這個操作是放到類方法內(nèi)部進行完成
      WZKPerson *person3=[WZKPerson personWithName:@"Kevin"];
        }
        return 0;
    }
    
(二) 自動內(nèi)存釋放總結(jié)
1. 基本用法
  • 自動內(nèi)存釋放使用@autoreleasepool關(guān)鍵字聲明一個代碼塊路召,如果一個對象在初始化時調(diào)用了autorelease方法,會將這個對象放到位于棧頂?shù)尼尫懦刂小?/li>
  • 當(dāng)代碼塊執(zhí)行完之后即當(dāng)自動釋放池被銷毀時波材,在塊中調(diào)用過autorelease方法的對象都會自動調(diào)用一次release方法股淡, 但是不一定能夠銷毀對象,例如:當(dāng)對象引用計數(shù)器值大于1時廷区,該對象就無法銷毀唯灵。
  • OC中類庫的類方法一般都不需要手動釋放,因為內(nèi)部已經(jīng)調(diào)用了autorelease方法隙轻。
2. 好處
  • 不需要再關(guān)心對象釋放的時間
  • 不需要再關(guān)心什么時候調(diào)用release
3. 使用注意
  • 由于自動釋放池最后統(tǒng)一銷毀對象埠帕,因此如果一個操作比較占用內(nèi)存,最好不要放到自動釋放池或者放到多個自動釋放池玖绿;應(yīng)該使用release來精確控制
  • 占用內(nèi)存較小的對象使用autorelease敛瓷,沒有太大的影響。
  • autorelease方法不會改變對象的引用計數(shù)器(銷毀時影響)斑匪,只是將這個對象放到自動釋放池中呐籽;
  • 系統(tǒng)自帶的方法中,如果不包含alloc秤标、 new 绝淡、copy等,則這些方法返回的對象都是autorelease的苍姜,如[NSDate date]牢酵。
  • 開發(fā)中經(jīng)常會寫一些類方法來快速創(chuàng)建一個autorelease對象,創(chuàng)建對象時不要直接使用類名衙猪,而是使用self馍乙。
4. 錯誤寫法
  • 連續(xù)調(diào)用多次autorelease布近,釋放池銷毀時執(zhí)行兩次release(-1嗎?)
  • Alloc之后調(diào)用了autorelease丝格,之后又調(diào)用了release撑瞧。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市显蝌,隨后出現(xiàn)的幾起案子预伺,更是在濱河造成了極大的恐慌,老刑警劉巖曼尊,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酬诀,死亡現(xiàn)場離奇詭異,居然都是意外死亡骆撇,警方通過查閱死者的電腦和手機瞒御,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來神郊,“玉大人肴裙,你說我怎么就攤上這事∮咳椋” “怎么了蜻懦?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長夕晓。 經(jīng)常有香客問我阻肩,道長,這世上最難降的妖魔是什么运授? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任烤惊,我火速辦了婚禮,結(jié)果婚禮上吁朦,老公的妹妹穿的比我還像新娘柒室。我一直安慰自己,他們只是感情好逗宜,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布雄右。 她就那樣靜靜地躺著,像睡著了一般纺讲。 火紅的嫁衣襯著肌膚如雪擂仍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天熬甚,我揣著相機與錄音逢渔,去河邊找鬼。 笑死乡括,一個胖子當(dāng)著我的面吹牛肃廓,可吹牛的內(nèi)容都是我干的智厌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼盲赊,長吁一口氣:“原來是場噩夢啊……” “哼铣鹏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哀蘑,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤诚卸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后绘迁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惨险,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年脊髓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栅受。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡将硝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屏镊,到底是詐尸還是另有隱情依疼,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布而芥,位于F島的核電站律罢,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏棍丐。R本人自食惡果不足惜误辑,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望歌逢。 院中可真熱鬧巾钉,春花似錦、人聲如沸秘案。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阱高。三九已至赚导,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赤惊,已是汗流浹背吼旧。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留未舟,地道東北人黍少。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓寡夹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親厂置。 傳聞我的和親對象是個殘疾皇子菩掏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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

  • 29.理解引用計數(shù) Objective-C語言使用引用計數(shù)來管理內(nèi)存,也就是說昵济,每個對象都有個可以遞增或遞減的計數(shù)...
    Code_Ninja閱讀 1,470評論 1 3
  • 內(nèi)存管理 簡述OC中內(nèi)存管理機制智绸。與retain配對使用的方法是dealloc還是release,為什么访忿?需要與a...
    丶逐漸閱讀 1,948評論 1 16
  • iOS內(nèi)存管理 概述 什么是內(nèi)存管理 應(yīng)用程序內(nèi)存管理是在程序運行時分配內(nèi)存(比如創(chuàng)建一個對象,會增加內(nèi)存占用)與...
    蚊香醬閱讀 5,694評論 8 119
  • 內(nèi)存管理是程序在運行時分配內(nèi)存瞧栗、使用內(nèi)存,并在程序完成時釋放內(nèi)存的過程海铆。在Objective-C中迹恐,也被看作是在眾...
    蹲瓜閱讀 3,001評論 1 8
  • 正確的臉部按摩手法珍语,可以說是瘦臉最快最直接的方法了锤岸,不僅可以讓你逐漸瘦出巴掌臉,還能使你的臉部肌膚變得年輕緊致板乙。每...
    你咋不下地閱讀 525評論 0 4