mrc下,oc記憶體管理遵循「誰建立、誰釋放、誰引用、誰管理」的機制,當建立或引用乙個物件時,需要向她傳送alloc,copy,retain訊息,當釋放該物件時需要傳送release訊息,當引用計數為零的時候,系統釋放該物件。
arc是自動引用計數,管理機制與手動機制一樣,只是不再需要呼叫retain,release,autorelease,它會在適當的位置插入release和autorelease。使用arc不代表不需要記憶體管理了,例如使用block時要避免迴圈引用,**作為屬性時,要用弱指標指引。
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的引用計數就會減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];。
記憶體管理機制
記憶體管理 jvm將記憶體分成三大主要區域 堆,棧,方法區,用來儲存資料。堆 堆中主要儲存引用型別物件,給成員變數分配空間。棧 jvm在執行程式時,在棧中會為每乙個方法都提供儲存空間叫棧幀,用來儲存方法中的區域性變數。方法區 用來儲存jvm載入的位元組碼檔案的資訊 類的資訊 包含類的方法,方法只有乙...
記憶體管理機制
記憶體管理是乙個作業系統必不可少 並且 非常重要的一環 linux 的成功 和它優秀的記憶體管理聯絡非常密切 因為乙個系統的高效性慾穩定性往往決定於它的記憶體管理機制 我項很多人吃過 dos 下 640k 的苦吧 前面我們介紹了 386 保護模式 從今天起我們將在此基礎上 分析 linux 的虛擬儲...
iOS 記憶體管理機制
學習要點 1.reference counting 引用計數機制 2.了解mrc apc和gc 3.autoreleasepool 執行機制 4.如何避免 retain cycle reference counting 引用計數機制 cocoa 上基本的記憶體管理機制就是引用計數,通過乙個 refe...