iOS 內存管理

ARC

ARC是 Object-C 編譯特性, 不是運行時特性也不是垃圾回收機制, ARC 所做的只是在代碼編譯自動在合適的地方插入 release 或 autorelese, 只要沒有強指針指向對象, 對象就會被釋放

  • 前端編譯器
    前端編譯器會為"擁有的"每一個對象插入相應的release語句. 如果對象的修飾符是 __strong, 那么它就是被擁有的. 如果再某個方法內創建了一個對象, 前端編譯器會為他的末尾自動插入 release 語句可以銷毀它. 而類擁有的對象會在 dealloc 方法內被釋放. 事實上, 你并不需要寫 dealloc 方法或者調用父類的方法, ARC 會自動幫你完成一切. 此外, ARC 生成的代碼甚至會比你寫的 release 語句的性能還要好, 因為編譯器可以做出一些假設. 在 ARC 中, 沒有類可以覆蓋 release方法, 也沒有調用它的必要. ARC 會通過直接使用objc_release 來優化調用過程. 而對于 retain 也是同樣的方法. ARC 會調用 objc_retain 來取代保留消息.
  • ARC 優化器
    雖然前端編譯器聽起來很流弊的樣子, 但是代碼中有事還是會出現對 retain 和 release 的重復調用. ARC 優化器負責移除多余的 retain 和release 語句. 確保生成的代碼運行速度高于手動引用計數的代碼

測試, 下面關于 Objective-C 內存管理的錯誤描述是

A. 當使用 ARC 來管理內存時, 代碼中不可以出現 autorelease
B. autoreLeasePool 在drain 的時候會釋放在其中分配的對象
C. 當使用 ARC 來管理內存的時候, 在線程中大量分配對象而不用 autoreleasepool 則可能會造成內存泄漏
D. 在使用 ARC 的項目中不能使用 NSZone

  • 參考答案: A
  • 理由: ARC 只是在大多時候編譯自動為我們添加上內存管理的代碼, 只是我們的源代碼看不到. 但是在編譯的時候會添加相關內存管理代碼. 對于自動釋放池, 在 drain 時會將自動釋放池中所有對象的應用計數減一, 若引用技術為 0, 則會自動釋放掉其內存. 如果在線程中需要大量分配內存, 我們理應添加自動釋放池, 以防內存泄漏. 比如在 for 循環中要分配大量的內存處理數據. 那么我們應該在 for 循環內添加自動釋放池, 在每個循環后釋放掉, 防止內存泄漏. 在 ARC 項目中, 自然不能手動使用 NSZone, 也不能調用父類的dealloc

MRC文件在ARC工程混編時, 需要在文件的 Compiler Flages 上添加什么參數

A. -shared B. -fno-objc-arc C. -fobjc-arc D. -dynamic
參考答案: B

什么情況使用 weak 關鍵字, 相比 assign 有什么不同

什么情況下使用 weak 關鍵字

  • 在 ARC 中, 在有可能出現循環引用的時候, 玩玩要讓其中一端使用 weak 來解決, 比如: delegate 代理屬性, blcok 里面的 self.
  • 自身已經對它進行一次強引用, 沒有必要再強引用一次, 此時也會使用 weak, 自定義 IBOutlet 控件一般也使用 weak: 當然, 也可以使用 strong.
    weak 和 assign 的不同
  • weak 此特質表明該屬性定義了一種"非擁有關系", 為這種屬性設置新值時, 設置方法既不保留新值, 也不釋放就只. 這個特性和 assign 類似, 然后在屬性所指的對象遭到摧毀時, 屬性值也會清空 (nil out). 而 assign 的 "設置方法" 只會執行對 "純量類型" (scalar type, 例如 CGFloat 或 NSInteger 等) 的簡單賦值操作
  • assign 可以用在非 OC 對象, weak 只能用在 OC 對象中.

調用對象的 release 方法會銷毀對象嗎

  • no no no, release 只是應用計數減 1 , 只有應用計數為 0 的時候對調用對象的 dealloc 方法進行釋放對象的內存.

下面代碼有木有什么問題呀

for (int i = 0; i < someLargeNumber; ++i)
{
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@"%@",string);
}

有問題的大兄弟, 每執行一次循環, 就會有一個 string 加到當前的 runloop 中的自動釋放池中, 只有當自動釋放池被 release 的時候, 自動釋放池中的 標示了 autorelease 的這些數據所占用的內存空間才能被釋放掉. 假設, 當 someLargeNumber 大到一定的成都的時候, 內存空間唄消耗干凈又沒有被釋放掉, 就會出現內存溢出.

  • 解決辦法 1 :如果 i 比較大, 可以用 @autoreleaseppol {} 解決, 放在 for 循環外, 循環結束后, 銷毀創建的對象, 解決占據棧區內存的問題
  • 解決方法 2 : 如果 i 不要臉的大, 一次訓話你都會造成自動釋放池被填滿, 自動釋放池放在 for 循環里面, 每次循環的時候都讓上一次創建的對象 release
    修改之后
for(int i = 0; i<1000;i++) {
  NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc] init];
  NSString *string = @"Abc";
  string = [string lowercaseString];
  string = [string stringByAppendingString:@"xyz"];
  NSLog(@"%@",string);
  // 釋放池
  [pool1 drain];
 }

Object-C 對象的內存布局是怎樣的

  • Objective - C 中沒有多繼承, 因此內存布局還是挺簡單的, 也就是: 最前面是 isa 指針, 然后父類的實例變量存放在子類的成員變量之前.

看下面代碼, 第一個 NSLog 會輸出什么, retainCount 是多少, 第二個和第三個呢, 為什么?

NSMutableArray* ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"];
[str retain];
[aryaddObject:str];
NSLog(@”%@%d”,str,[str retainCount]);
[str retain];
[str release];
[str release];
NSLog(@”%@%d”,str,[str retainCount]);
[aryremoveAllObjects]
NSLog(@”%@%d”,str,[str retainCount]);
  • 第一個是3, retain + 1, 加入數組自動 + 1, retainCount + 1, 總的為3
  • 第二個是2, retain + 1, release - 1, release - 1. 值為2
  • 最后一個1, 數組刪除 -1. 得到結果為1.

看看下面 person 的 retainCount 值

Person * per = [[Person alloc] init];
self.person = per;
  • 第一句代碼 person 的 retainCount 的值是 1
  • 在 self.person 時 , 分三種情況
    • assign 修飾, 值不變, 還為 1
    • retain 修飾, + 1, 變為 2
    • copy 修飾, 值不變, 還為1

什么時候需要在程序中創建內存池

  • 用戶自己創建的數據線程, 炫耀創建改線程的內存池

我們不創建內存池, 時候有內存池提供給我們.

  • 界面線程維護自己的內存池, 用戶自己創建的數據線程, 則需要創建改線程的內存.

蘋果怎么實現 autoreleasepool的

autoreleasepool 以一個隊列數組的形式實現, 主要通過以下三個函數完成,

  • objc_autoreleasepoolPush
  • objc_autoreleasepoolPop
  • objc_autorelease
    根據函數名可知道, 對 autorelease 分別執行 push, pop 操作. 銷毀對象時執行 release 操作.

objc使用什么機子管理對象內存

  • 通過引用計數器的機子來決定對象是否需要釋放. 每次 runloop 完成一個循環的時候, 都會檢查對象的 retainCount, 如果 retainCount, 如果retainCount 為0, 說明該對象沒有地方需要繼續使用了, 可以釋放掉

為什么要進行內存管理

  • 因為移動設備的內存及其有限, 當一個程序說占內存達到一定數值的時候, 系統會發出內存警告, 當程序達到更大的值的時候, 程序會出現閃退, 影響用戶體驗. 為了保證程序的運行流暢, 必須進行內存管理.
  • 內存管理的范疇
  • 管理所有繼承自 NSObject 的對象, 對基本數據類型無效, 是因為對象和其他數據類型在系統中儲存的控件是不一樣的, 其他局部變量主要存儲在棧區(因為基本類型占用的存儲空間是固定的, 一般存放在棧區), 而對象存儲在堆中, 當代碼塊結束的時候, 這個代碼塊會設計到所有局部變量會自動彈棧清空, 指向對象的指針也會被回收, 這時對象就沒有指針指向, 但依然存在于堆內存中, 造成內存泄漏.

objc 使用什么機子管理對象內存(或者內存管理方式有哪些)

  • MRC (manual retain-release)手動內存管理
  • ARC (automatic reference counting) 自動引用計數
  • Garbage collection (垃圾回收). 但是 iOS 不支持垃圾回收, ARC 作為 LLVM 3.0 編譯器的一項特性, 在 iOS 5.0 (Xcode-4)版本后推出的.
  • ARC 的判斷準則, 只要沒有強指針指向對象, 對象就會被釋放.

內存管理原則

  • 只要還有人在使用這個對象, 那么這個對象就不會被回收
  • 只有你想使用這個對象, 那么就應該讓這個對象的引用計數器加1
  • 當你不想使用這個對象時, 應該讓對象的引用計數器減1
  • 誰創建, 就由誰來release
    • 如果你通過alloc, new, copy 來創建一個對象, 當你不想用這個對象的時候就必須調用release 或者autorelease 讓引用計數器減1
    • 不是你創建的就不用你負責 release
      誰retain 誰release
  • 只要你調用了retain ,無論這個對象如何生成, 都需要調用release
    總結:
  • 有加就應該有減, 曾讓某個計數器加1, 就應該讓其在最后減1

內存管理研究對象

  • 野指針: 指針變量沒有進行初始化或者指向的空間已經被釋放了
    • 使用野指針調用對象方法, 會報異常, 程序崩潰
    • 通常再調用玩 release 方法后, 把 保存對象指針的地址清空, 賦值為 nil, 找 oc 中沒有空指針異常, 所以[nil retain] 調用方法不會有異常
  • 內存泄漏
    • 如 Person *person = [Person new]; (對象提前賦值nil或者清空)在棧區的person已經被釋放, 而堆區new 產生的對象還沒有釋放, 就會造成內存泄漏.
    • 僵尸對象: 堆中已經被釋放的對象(retainCount = 0)
  • 空指針: 指針賦值為空, nil

未完待續

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容