1. 程式人生 > >iOS的記憶體管理

iOS的記憶體管理

      iOS記憶體管理機制的原理是引用計數,引用計數簡單來說就是統計一塊記憶體的所有權,當這塊記憶體被創建出來的時候,它的引用計數從0增加到1,表示有一個物件或指標持有這塊記憶體,擁有這塊記憶體的所有權,如果這時候有另外一個物件或指標指向這塊記憶體,那麼為了表示這個後來的物件或指標對這塊記憶體的所有權,引用計數加1變為2,之後若有一個物件或指標不再指向這塊記憶體時,引用計數減1,表示這個物件或指標不再擁有這塊記憶體的所有權,當一塊記憶體的引用計數變為0,表示沒有任何物件或指標持有這塊記憶體,系統便會立刻釋放掉這塊記憶體。

      其中在開發時引用計數又分為ARC(自動記憶體管理)和MRC(手動記憶體管理)。ARC的本質其實就是MRC,只不過是系統幫助開發者管理已建立的物件或記憶體空間,自動在系統認為合適的時間和地點釋放掉已經失去作用的記憶體空間,原理是一樣的。雖然ARC操作起來很方便,不但減少了程式碼量,而且降低了記憶體出錯的概率,但因為ARC不一定會及時釋放,所以程式有時候可能會佔用記憶體較大。而MRC若做得好,通過手動管理,及時釋放掉不需要的記憶體空間,便可保證程式長時間執行在良好狀態上。

     在MRC中會引起引用計數變化的關鍵字有:alloc,retain,copy,release,autorelease。(strong關鍵字只用於ARC,作用等同於retain)

     alloc:當一個類的物件建立,需要開闢記憶體空間的時候,會使用alloc,alloc是一個類方法,只能用類呼叫,它的作用是開闢一塊新的記憶體空間,並使這塊記憶體的引用計數從0增加到1,注意,是新的記憶體空間,每次用類alloc出來的都是一塊新的記憶體空間,與上一次alloc出來的記憶體空間沒有必然聯絡,而且上一次alloc出來的記憶體空間仍然存在,不會被釋放。

     retain:retain是一個例項方法,只能由物件呼叫,它的作用是使這個物件的記憶體空間的引用計數加1,並不會新開闢一塊記憶體空間,通常於賦值是呼叫,如:

物件2=[物件1 retain];表示物件2同樣擁有這塊記憶體的所有權。若只是簡單地賦值,如:物件2=物件1;那麼當物件1的記憶體空間被釋放的時候,物件2便會成為野指標,再對物件2進行操作便會造成記憶體錯誤。

     copy:copy同樣是一個例項方法,只能由物件呼叫,返回一個新的物件,它的作用是複製一個物件到一塊新的記憶體空間上,舊記憶體空間的引用計數不會變化,新的記憶體空間的引用計數從0增加到1,也就是說,雖然內容一樣,但實質上是兩塊記憶體,相當於克隆,一個變成兩個。其中copy又分為淺拷貝、深拷貝和真正的深拷貝,淺拷貝只是拷貝地址與retain等同;深拷貝是拷貝內容,會新開闢新記憶體,與retain不一樣;真正的深拷貝是對於容器類來說的,如陣列類、字典類和集合類(包括可變和不可變),假設有一個數組類物件,普通的深拷貝會開闢一塊新記憶體存放這個物件,但這個陣列物件裡面的各個元素的地址卻沒有改變也就是說陣列元素只是進行了retain或者淺拷貝而已,並沒有建立新的記憶體空間,而真正的深拷貝,不但陣列物件本身進行了深拷貝,連陣列元素都進行了深拷貝,即為各個陣列元素開闢了新的記憶體空間。

     release:release是一個例項方法,同樣只能由物件呼叫,它的作用是使物件的記憶體空間的引用計數減1,若引用計數變為0則系統會立刻釋放掉這塊記憶體。如果引用計數為0的基礎上再呼叫release,便會造成過度釋放,使記憶體崩潰;

     autorelease:autorelease是一個例項方法,同樣只能由物件呼叫,它的作用於release類似,但不是立刻減1,相當於一個延遲的release,通常用於方法返回值的釋放,如便利構造器。autorelease會在程式走出自動釋放池時執行,通常系統會自動生成自動釋放池(即使是MRC下),也可以自己設定自動釋放池,如:

@autoreleasepool{

obj= [[NSObject alloc]init];

[obj autorelease];

}

當程式走出“}”時obj的引用計數就會減1.

      除了以上所述的關鍵字,還有一些方法會引起引用計數的變化,如UI中父檢視新增、移除子檢視,導航控制器或檢視控制器推出新的檢視控制器以及返回,容器類(陣列、字典和集合)新增和移除元素。

      當子檢視新增到父檢視上時,子檢視的引用計數加1,移除時引用計數減1,若父檢視引用計數變為0記憶體被釋放,其所有的子檢視都會被release一次,即引用計數減1,原則上只有這三種情況子檢視的引用計數會發生變化,其他如父檢視引用計數的加減都不會影響到子檢視。

      容器類的情況與檢視類似,新增元素,該元素引用計數加1,移除元素,該元素引用計數減1,容器引用計數變為0所佔用記憶體被釋放,容器所有元素release,引用計數減1,其他情況下容器本身的引用計數變化不會影響到容器內元素的引用計數變化。

      導航控制器或檢視控制器推出新的檢視控制器會使被推出的檢視控制器的引用計數加1,該檢視控制器返回的時候引用計數減1,具體方法如下:

導航控制器推出檢視控制器呼叫方法:- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;

返回時同樣用導航控制器呼叫方法:- (UIViewController *)popViewControllerAnimated:(BOOL)animated;

檢視控制器推出檢視控制器呼叫方法:- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion

返回時被推出的檢視控制器呼叫方法:- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion

      應注意:當一個物件的引用計數變為0佔用記憶體被釋放時,會呼叫- (void)dealloc方法,所以如果在MRC下自定義類,必須在該方法裡將該類中屬性關鍵字設定為retain或copy的屬性release一次,以免造成記憶體洩露,重寫方法不要忘記在第一行新增[super dealloc];。

相關推薦

iOS 記憶體管理研究

iPhone 作為一個移動裝置,其計算和記憶體資源通常是非常有限的,而許多使用者對應用的效能卻很敏感,卡頓、應用回到前臺丟失狀態、甚至 OOM 閃退,這就給了 iOS 工程師一個很大的挑戰。 網上的絕大多數關於 iOS 記憶體管理的文章,大多是圍繞 ARC/MRC、迴圈引用的原理或者是如何找尋記憶體洩漏來展

Objective-C runtime機制(5)——iOS 記憶體管理

概述 當我們建立一個物件時: SWHunter *hunter = [[SWHunter alloc] init]; 上面這行程式碼在棧上建立了hunter指標,並在堆上建立了一個SWHunter物件。目前,iOS並不支援在棧上建立物件。 iOS 記憶體分割槽 iOS

iOS記憶體管理的那些事兒-原理及實現

作者簡介 boyce,餓了麼物流團隊資深iOS開發。曾在格瓦拉等公司從事iOS相關研發工作。 注:本篇文章是《iOS記憶體管理的那些事兒》系列文章的第一部分。稍後我們會持續更新第二部分(開源監測記憶體洩漏的實現)和第三部分(如何利用開源工具做相關的APM),感興趣的童鞋可以關注我們專欄並獲取實

iOS 記憶體管理(補充)

  物件操作 OC中對應的方法 對應的 retain Count 變化 生成並持有物件 alloc/new/copy/mutableCopy等 +1 內容單元

iOS記憶體管理知識點梳理

1.iOS記憶體管理區域分為以下5個區域: 棧區,堆區,靜態區,常量區在記憶體分佈中以由高地址向低地址分佈的. (1).棧區(stack):它是有編譯器自動分配和管理的,存放區域性變數,函式的引數值.例如: - (NSString *)encodeBase64String:(NSString

iOS 進階—— iOS 記憶體管理 & Block

第一篇 iOS 記憶體管理 1 似乎每個人在學習 iOS 過程中都考慮過的問題 alloc retain release delloc 做了什麼? autoreleasepool 是怎樣實現的? __unsafe_unretained 是什麼? Block 是怎樣實現的 什麼

IOS記憶體管理知識總結(一)

    最近優化公司在優化app,總結幾個記憶體管理的知識點。    首先我們要清楚    1. “堆”和“棧” Objective-C的物件在記憶體中是以堆的方式分配空間的,並且堆記憶體是由你釋放的,就是releaseOC物件存放於堆裡面(堆記憶體要程式設計師手動回收)非

IOS記憶體管理--自動釋放池的實現原理

原文連結:http://www.cocoachina.com/ios/20150610/12093.html 記憶體管理一直是學習 Objective-C 的重點和難點之一,儘管現在已經是 ARC 時代了,但是瞭解 Objective-C 的記憶體管理機制仍然是十分必要的。其中,弄清楚 auto

iOS記憶體管理

記憶體管理原則 自己生成的物件,自己持有 非自己生成的物件,自己也能持有 不在需要自己持有的物件時釋放 非自己持有的物件無法釋放 自己生成的物件,自己持有 使用 alloc/new/copy/mutableCopy 名稱開頭的方法名意味著自己生成的

iOS記憶體管理記憶體洩露除錯的常用技巧

在往下看之前請下載例項MemoryProblems,我們將以這個工程展開如何檢查和解決記憶體問題。 懸掛指標問題 懸掛指標(Dangling Pointer)就是當指標指向的物件已經釋放或回收後,但沒有對指標做任何修改(一般來說,將它指向空指標),而是仍然指向原來已經回收的地址。如

iOS 進階—— iOS記憶體管理

1 似乎每個人在學習 iOS 過程中都考慮過的問題     alloc retain release delloc 做了什麼?     autoreleasepool 是怎樣實現的?     __unsafe_unretained 是什麼?     Block 是怎樣實現的     什麼時候會引起迴圈引用,

iOS 記憶體管理基本原則

我們知道objc中建立物件是存放在堆中的(基本資料型別除外,是由系統自己管理,並存放在棧中),系統不會自動釋放堆中的記憶體。如果建立完的物件存放在堆中後並使用完沒有得到及時的釋放,會佔用的記憶體。但是

2-2 iOS 記憶體管理,棧,堆,BSS段,資料段,程式碼段,野指標,殭屍物件

記憶體管理,拆開講就是對如何將資料儲存到記憶體中,如何釋放記憶體中的資料,什麼時候釋放。記憶體中的六大區域記憶體分為5個區域,分別指的是----->棧區/堆區/BSS段/資料段/程式碼段棧:儲存區

IOS記憶體管理,ARC,MRC,自動釋放池(基礎)

在IOS中記憶體管理幾乎是每個人必須知道的一個知識點。首先我們總結一下MRC,再通過MRC來認識ARC以及自動釋放池 1.MRC 1.1 淘汰的技術 1.2 引用計數(RC)是指alloc自動分配的一塊兒儲存空間,用於儲存持有該空間的指標個數 1.3 使

Objective-C高階程式設計:iOS與OS X多執行緒和記憶體管理

這篇文章主要給大家講解一下GCD的平時不太常用的API,以及文末會貼出GCD定時器的一個小例子。 需要學習的朋友可以通過網盤免費下載pdf版 (先點選普通下載-----再選擇普通使用者就能免費下載了)http://putpan.com/fs/cy1i1beebn7s0h4u9/ 1.G

[讀書筆記]iOS與OS X多執行緒和記憶體管理 [GCD部分]

3.2 GCD的API 蘋果對GCD的說明:開發者要做的只是定義想執行的任務並追加到適當的Dispatch Queue中。 “Dispatch Queue”是執行處理的等待佇列。通過dispatch_async函式等API,在Block

iOS面試之——記憶體管理

記憶體管理 1.什麼是ARC? ARC是automatic reference counting自動引用計數,在程式編譯時自動加入retain/release。在物件被建立時retain count+1,在物件被release時count-1,當count=0時,銷燬物件。程式中加入

理解iOS 和 macOS 的記憶體管理

在 iOS 和 macOS 應用的開發中,無論是使用 Objective-C 還是使用 swift 都是通過引用計數策略來進行記憶體管理的,但是在日常開發中80%以上的情況,我們不需要考慮記憶體問題,因為 Objective-C 2.0 引入的自動引用計數(ARC)技術為開發者們自動的完成了

iOS NSMutableArray 的記憶體管理原理

我一直想知道NSMutableArray內部如何運作。不要誤會我的意思,不可變陣列肯定會帶來巨大的好處。它們不僅是執行緒安全的,而且複製它們基本上是免費的。它並沒有改變它們非常沉悶的事實 - 它們的內容無法修改。我發現實際的記憶體操作細節令人著迷,這就是本文關注可變陣列的原因。 由於我或多或

理解 iOS 和 macOS 的記憶體管理

在 iOS 和 macOS 應用的開發中,無論是使用 Objective-C 還是使用 swift 都是通過引用計數策略來進行記憶體管理的,但是在日常開發中80%(這裡,我瞎說的,8020 原則嘛?)以上的情況,我們不需要考慮記憶體問題,因為 Objective