Objective-C 內(nèi)存管理(上)學(xué)習(xí)筆記


一.開篇之初

  1. 內(nèi)存管理解決的問題就是:

    1)防止野指針的生成
    (野指針:指向變量的指針還存在请垛,但是所指向的內(nèi)存已經(jīng)被釋放锨匆,此時的指針就變成了野指針 -- 沒有指向 “ 內(nèi)容 ” 的指針)

    2)防止出現(xiàn)內(nèi)存泄漏
    (內(nèi)存泄漏:指向內(nèi)存空間的指針已經(jīng)被釋放封救,但是該指針指向的內(nèi)存空間還在內(nèi)存中存在(被占用) -- 沒有 “ 地址 ” 的內(nèi)存)

    3)合理使用內(nèi)存,防止有限內(nèi)存的大量消耗

  2. Objective-C的內(nèi)存管理有三種圣勒,其中iOS中能用的膝迎,就是MRC(手動引用計數(shù))和ARC(自動引用計數(shù),官方推薦使用)灰蛙;而另外一個垃圾回收機制祟剔,只能用在OS X系統(tǒng)中。

  3. 內(nèi)存管理管理的范圍是摩梧,Objective-C 對象(基本數(shù)據(jù)類型由系統(tǒng)自動管理)物延。

  4. MRC是基于引用計數(shù)的內(nèi)存管理,是否釋放內(nèi)存取決于引用計數(shù)是否為0仅父;但注意叛薯,真正要研究并不是引用計數(shù)浑吟,而是對象是否被持有的問題。

  5. ARC是基于自動引用計數(shù)的內(nèi)存管理耗溜,是否釋放內(nèi)存取決于對象是否還有強引用指向组力;真正研究的是,對象的所有權(quán)問題抖拴。(所有權(quán)的概念是ARC中引入的)


二.內(nèi)存管理的思考方式

引自:《Objective-C高級編程 iOS與OS X多線程和內(nèi)存管理》

  • 自己生成的對象燎字,自己所持有
  • 非自己生成的對象,自己也能持有
  • 自己持有的對象不再需要時釋放
  • 非自己持有的對象無法釋放

換個方式來解讀:

  • 自己申請的內(nèi)存阿宅,自己所掌管(擁有)
  • 不是自己申請的內(nèi)存候衍,自己也可以掌管(擁有)
  • 自己掌管(擁有)的內(nèi)存不再需要時就釋放(free)
  • 不是自己掌管(擁有)的內(nèi)存,無法釋放(free)

三.MRC(Manual Reference Counting)內(nèi)存管理

--> 小小結(jié) <--

  • MRC模式下對象什么時候被銷毀洒放?引用計數(shù)值為0的時候蛉鹿。

  • MRC使用的管理內(nèi)存的基本方法和屬性:

    • 四個方法 --> retain/release/dealloc/autorelease/
    • 一個屬性 --> retainCount(記錄引用計數(shù)值)
      <strong><----均定義在 NSObject.h 中----></strong>
//define OBJC_ARC_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
- (instancetype)retain OBJC_ARC_UNAVAILABLE;
- (oneway void)release OBJC_ARC_UNAVAILABLE;
- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;
- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
  • 誰retain,誰release
  • retain既是把retainCount值加 1往湿; release既是把retainCount值減 1
  • dealloc只有在 retainCount = 0 的時候妖异,由系統(tǒng)自動調(diào)用
  • autorelease是把對象加進自動釋放池中,由系統(tǒng)自動為池中的對象發(fā)送release消息

  • 問題 1:什么是引用計數(shù)(Reference Counting)煌茴?

  • 引用計數(shù) ?

這里的“計數(shù)”表明必然會有一個東西(變量)來記錄引用的變化随闺,而在OC里這個變量就是retainCount;那么還有一個問題就是通過什么方式來操作這個變量蔓腐,OC里就是retain(引用次數(shù)加 1)矩乐,release(引用計數(shù)減 1 )方法。

  • 引用計數(shù):就是分配的<strong> 內(nèi)存區(qū)塊 </strong>被<strong> 多少個 </strong>OC對象所持有(掌管回论;保持且擁有)散罕,間接表示就是retainCount值的大小。

注:對象傀蓉,指人可以識別的東西欧漱,具備屬性、收發(fā)信息葬燎、處理信息误甚;而從系統(tǒng)的角度看,操作對象就是操作一塊內(nèi)存谱净。(可能不是很準(zhǔn)確......)

  • 問題 2 :引用計數(shù)如何管理OC對象窑邦?

  • 首先明確,引用計數(shù)的變化是被持有者的變化壕探。

  • 那么問題就是怎樣持有對象(持有內(nèi)存)?

  • 持有:就是可以訪問內(nèi)存冈钦,且可以進行讀寫操作,而一般是通過內(nèi)存的首地址進行內(nèi)存的訪問李请,就是指針訪問瞧筛。

  • 而OC中一般用來分配內(nèi)存的的函數(shù)是alloc/new/copy/mutablecopy(當(dāng)然還有clloc...等等)厉熟,它們返回的都是指針,就是使用他們來生成對象并持有對象的较幌。

  • 問題 3:持有揍瑟?釋放?銷毀乍炉?對象... , 請看下表:

OC操作方法 對象的操作 retainCount
alloc/new/copy/mutablecopy等 生成并持有對象 1月培?
retain 持有對象 +1
release 釋放對象 -1
dealloc 銷毀對象 此時該值沒有意義
autorelease 在自動釋放池結(jié)束時,為里面的對象發(fā)送一條release消息 (all object) -1

上面涉及的方法定義如下(NSOject.h):

//define OBJC_SWIFT_UNAVAILABLE(_msg) __attribute__((availability(swift, unavailable, message=_msg)))
+ (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
- (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");

- (id)copy;
- (id)mutableCopy;
  • 問題 4:什么是自動釋放池恩急?

  • 自動釋放池:在自動釋放池結(jié)束時,系統(tǒng)自動為里面的對象發(fā)送一條release消息(when the pool itself is drained)

  • 要使用自動釋放池就要使用NSAutoreleasePool對象

NSAutoreleasePool
  • NSAutoreleasePool它的方法
  • 使用方法:

  • 創(chuàng)建一個NSAutoreleasePool對象
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  • 添加要釋放的對象進NSAutoreleasePool對象中
    id obj = [NSString alloc] initWithstring:@"objective-c pool"];
    [obj autorelease];[pool addObject:obj]; --- 1

  • 釋放NSAutoreleasePool對象
    [pool drain];等同于[pool release]; --- 2

注意:
1 --> 建議使用autorelease方法纪蜒,因為后面的方法會導(dǎo)致同一個對象被多次加入自動釋放池中衷恭。

addObject:方法

2 --> 雖然兩個方法效果等同,但還是建議使用自動釋放池專門的drain方法纯续。
drain方法

  • 補充autorelease方法


    autorelease方法
  • 問題 5:MRC下如何防止野指針訪問?

  • 野指針訪問:指向的內(nèi)存空間已經(jīng)被釋放了随珠,但是指針還指向著已經(jīng)被釋放的內(nèi)存,此時的指針就是野指針猬错。

  • 訪問了不存在的內(nèi)存窗看,當(dāng)然會引起程序崩潰

  • 修改Xcode工程為MRC模式

  • 開啟對應(yīng)targets的僵尸對象檢測,詳細(xì)步驟如下:


    選擇Edit Scheme
勾選僵尸對象檢測
  • 情況 1:過快釋放了對象(不要理retaiinCount把注意力放在對象被持有的個數(shù)上)

  • retainCount的補充:


    只能用在調(diào)試階段倦炒,值是不可靠的
  • 程序代碼和運行結(jié)果


    tesh.m
main.m
指向異常的代碼
  • 問題 6:MRC下如何防止內(nèi)存泄漏显沈?

  • 自己生成的對象,自己所持有

  • 非自己生成的對象逢唤,自己也能持有

  • 自己持有的對象不再需要時釋放

  • 非自己持有的對象無法釋放

補充:


持有對象
運行結(jié)果

疑問:mArrayCopy的retainCount是2 ?被持有者有兩個拉讯?

再來一次release

從這里就可以證明了,cope出來的新對象只是被mArrayCopy自己所持有而已鳖藕,所以當(dāng)release一次的時候?qū)ο笠呀?jīng)被釋放了魔慷,如果再release就是野指針訪問了(注:直接看持有者有多少)。

代碼:

    /**
     *  alloc就是分配內(nèi)存的意思著恩,返回了一個指向內(nèi)存首地址的指針
     */
    NSMutableArray *mArrayAlloc = [[NSMutableArray alloc] init];  // mArrayAlloc 持有對象
    /**
     *  new 就相當(dāng)于alloc+init,但是new有可能會返回同一個對象院尔,所以并不建議使用
     */
    NSMutableArray *mArrayNew = [NSMutableArray new];   // mArrayNew 持有對象
    
    /**
     *  copy是一個實例方法,具體如下:
     *  - (id)copy
     *  Returns the object returned by copyWithZone:.
     *  - (id)copyWithZone:(NSZone *)zone
     *  Returns a new instance that’s a copy of the receiver.
     *  ---new instance 就表明了創(chuàng)建了一個新的內(nèi)存喉誊,并返回首地址(id 相當(dāng)于 void *)
     */
    NSMutableArray *mArrayCopy = [mArrayAlloc copy];   //mArrayCopy 持有了對象
    
    /**
     *  Returns the object returned by mutableCopyWithZone:.
     *  - (id)mutableCopy
     *  - (id)mutableCopyWithZone:(NSZone *)zone
     *  Returns a new instance that’s a mutable copy of the receiver.
     *  ---new instance 就表明了創(chuàng)建了一個新的內(nèi)存邀摆,并返回首地址(id 相當(dāng)于 void *)
     */
    NSMutableArray *mArrayMutablecopy = [mArrayNew mutableCopy];//mArrayMutablecopy 持有了對象
  • 持有對象
源代碼
運行結(jié)果
明顯的野指針訪問了
  • 使用copy來獨立管理內(nèi)存
使用copy源代碼
內(nèi)容沒有改變
  • 如果內(nèi)存還在使用的話,當(dāng)然不要把對象賦值為nil

  • 對象之間相互持有的情況

  • 程序代碼


    Apple.h
Apple.m
Girl.h
Girl.m
main.m

如果要達到目的裹驰,apple讓girl也持有隧熙,就要在girl得到apple的時候持有一下,而可以做持有操作的是retain幻林,來看看:

內(nèi)存泄漏

我們知道對象在最后銷毀的時候是調(diào)用了dealloc方法的贞盯,那么girl既然持有了apple那么在銷毀自己的時候是不是應(yīng)該把自己持有的東西給交出來(釋放掉)音念,已死的對象不可能持有東西了吧,所以在girl的dealloc方法中加上apple釋放的代碼:

雖然上面的方法是可以的躏敢,但是有問題闷愤,問題如下:

retain

apple再持有一下[[Apple alloc] init],再給girl件余,直接翻譯都是問題讥脐,而且從封裝性來看,girl要持有apple應(yīng)該是自己去持有啼器,也就是要自己進行retain烂瘫,而不是要apple先retain再給girl,

代碼優(yōu)化:


retain去掉
set方法中進行retain

還有立磁,如果我們從現(xiàn)實生活中考慮問題(面向?qū)ο笫乾F(xiàn)實世界的抽象)韩玩,girl會不會只要一次apple呢?多要幾個~~

為了防止內(nèi)存泄漏损谦,我得這么干岖免,估計你看到這就想呵呵了:


正常釋放

再次優(yōu)化代碼,目的是只要girl再次要一個新的apple就給它持有照捡,如果是拿原來的apple當(dāng)然不再次持有咯:

做if判斷
正常釋放

代碼修改成下面這樣就是真正的颅湘,girl直接的持有一個新的apple(新的內(nèi)存空間)了,不過結(jié)果是一樣的栗精,正常釋放:


ARC( Automatic Reference Counting)內(nèi)存管理

  • 請期待下一篇......
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闯参,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子悲立,更是在濱河造成了極大的恐慌赢赊,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件级历,死亡現(xiàn)場離奇詭異释移,居然都是意外死亡,警方通過查閱死者的電腦和手機寥殖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門玩讳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嚼贡,你說我怎么就攤上這事熏纯。” “怎么了粤策?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵樟澜,是天一觀的道長。 經(jīng)常有香客問我,道長秩贰,這世上最難降的妖魔是什么霹俺? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮毒费,結(jié)果婚禮上丙唧,老公的妹妹穿的比我還像新娘。我一直安慰自己觅玻,他們只是感情好想际,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著溪厘,像睡著了一般胡本。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上畸悬,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天打瘪,我揣著相機與錄音,去河邊找鬼傻昙。 笑死,一個胖子當(dāng)著我的面吹牛彩扔,可吹牛的內(nèi)容都是我干的妆档。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼虫碉,長吁一口氣:“原來是場噩夢啊……” “哼贾惦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起敦捧,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤须板,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后兢卵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體习瑰,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年秽荤,在試婚紗的時候發(fā)現(xiàn)自己被綠了甜奄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡窃款,死狀恐怖课兄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晨继,我是刑警寧澤烟阐,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響蜒茄,放射性物質(zhì)發(fā)生泄漏唉擂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一扩淀、第九天 我趴在偏房一處隱蔽的房頂上張望楔敌。 院中可真熱鬧,春花似錦驻谆、人聲如沸卵凑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勺卢。三九已至,卻和暖如春象对,著一層夾襖步出監(jiān)牢的瞬間黑忱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工勒魔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留甫煞,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓冠绢,卻偏偏與公主長得像抚吠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子弟胀,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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