1. 程式人生 > >iOS記憶體管理知識點梳理

iOS記憶體管理知識點梳理

1.iOS記憶體管理區域分為以下5個區域:

棧區,堆區,靜態區,常量區在記憶體分佈中以由高地址向低地址分佈的.

(1).棧區(stack):它是有編譯器自動分配和管理的,存放區域性變數,函式的引數值.例如:

- (NSString *)encodeBase64String:(NSString *)input {

    NSString *str =[inputstringByAppendingString:@"test"];

    NSData *data = [strdataUsingEncoding:NSUTF8StringEncoding];

    NSString *base64String= [database64EncodedStringWithOptions:0];

    return base64String;

}

方法帶的引數input會被壓入發起呼叫的程序棧中,待到呼叫結束後,函式的返回值base64String也回被存放回棧中;

(2).堆區:由程式設計師分配和釋放,存放程序執行中被動態分配的記憶體。呼叫alloc,copy,new會動態分配記憶體;當利用realse,autorealse時,當物件的引用計數為0時,這部分記憶體將被回收,我們所說的記憶體管理主要指這塊.

(3).靜態區:比如static宣告的變數;

(4).常量區:儲存常量.

(5).用來存放函式的二進位制程式碼.

2.棧區和堆區記憶體管理方式

(1).棧區由系統自動管理,自動分配,自動釋放;

(2).堆區由程式設計師手動管理,本著誰建立,誰釋放的原則;

3.記憶體管理修飾符

ARC提供__strong, __weak, __autoreleasing, __unsafe_unretained四種修飾符.

(1).__strong:強引用,持有物件的所有權,也是預設情況下的物件修飾符,如需強行釋放,置為nil;

(2).__weak:弱引用,不持有物件的所有權,指向的物件的記憶體被系統回收時,自身會被置為nil.

4.屬性記憶體管理

屬性記憶體管理分為兩類,基本資料型別和物件型.

基本資料型別預設修飾符為(atomic,readwrite,assign);

物件型預設修飾符為(atomic,readwrite,strong).

第三個修飾符為記憶體管理修飾符,有assign,retain,copy,strong,weak.

(1).assign:一般修飾基本資料型別,也可以修飾物件型,用assign修飾物件,不持有物件,不會讓物件的引用技術+1,但是如果修飾物件,物件記憶體被回收時,指向指標仍指向這片區域,形成野指標,導致崩潰.

(2).retain:兩個物件地址相同(指標拷貝)內容相同,兩個物件要改變就一起改變,多個指標指向同一片記憶體區域上的物件.

(3).copy:建立一個新物件(物件拷貝)兩個物件內容相同,舊物件沒有變化,舊物件發生改變不影響新物件.

(4).strong:強引用,導致物件引用計數+1.

(5).weak:弱引用,不持有物件,物件引用計數不會變化.

5.記憶體修飾符兩兩對比

(1).assign和weak:objc物件被釋放,weak指標會只自動置nil(安全),assin不會(不安全).

(2).copy和retain:copy是物件拷貝,生成新物件,開闢新記憶體,值不隨著變化而變化;retain是指標拷貝,生成新的指標,指向同一片記憶體,值隨著變化為變化.

(3).strong和retain:ARC下完全相同,MRC下,修飾block,retain和strong會不同,當然正確修飾還是copy.

(4).strong和weak:strong持有物件,引用技術+1;weak不持有物件,引用計數不變.

(5).strong和copy:copy是物件拷貝,生成新物件,開闢新記憶體,值不隨著變化而變化;strong是指標拷貝,生成新的指標,指向同一片記憶體,值隨著變化為變化.

6.自動釋放池autoreleasepool

autorealeasepool大家都能熟悉,我只談三點:

(1).釋放時機

對於每一個新的RunLoop,系統都會隱形的建立一個autoreleasepool,RunLoop結束時自動釋放池會進行物件的釋放操作. autorelease和release的區別主要是引用計數減一的時機不同,autorelease會在物件的使用真正結束的時候才做引用計數減1,而不是收到訊息立馬釋放。

(2)ARC下autorealeasepool的應用場景

比如在一個迴圈中建立大量的比變數,可以建立內部的池子來降低記憶體佔峰值,自動釋放池一定要放在迴圈內部.

(3)autorealeasepool注意事項

自動釋放池實質上只是在釋放的時候給池中所有物件傳送release訊息,不保證物件一定會銷燬,如果自動釋放池向物件傳送release訊息後物件的引用技能仍大於1,物件就無法銷燬;

autorelease不會改變物件的引用計數.

7.記憶體管理與block

(1).一般使用copy來進行修飾.可以不寫,ARC下編譯器自動進行copy操作,儘量不要使用retain;

(2).block會對內部使用的物件進行強引用,因此使用時應該確定不會引起迴圈引用.可以採取以下方法避免:

1.弱引用標記__weak;

2.使用__block修飾,但是使用結束後block內部要對物件指標置為nil,並且這個block至少執行一次;

3.將要使用物件以block引數的形式傳入,block就不會捕獲該物件,而將其作為引數使用,其生命週期的棧自動管理,不會造成記憶體洩漏

(3).使用__block修飾物件,實際上是把在棧上建立的自動變數封裝成了一個機構體,在堆上建立,以方便從棧和堆上訪問和修改同一份資料.

8.關於delloc

delloc是alloc的是相對的,delloc是當物件的引用計數為0的使用,系統自動呼叫,當然我們也可以改寫它,最典型的例子就是移除通知的時候,需要重寫delloc方法;

如果delloc沒有被系統呼叫,證明物件本身還有持有者,需要檢查持有者,多半由於迴圈引用導致;

從delloc分析迴圈引用:物件的屬性和方法,其他例項變數,被釋放的條件是物件本身呼叫delloc方法,而當出現迴圈引用時,物件本身的引用計數大於0,不會呼叫delloc,就會出現互相等待對方釋放,而又互相持有對方的僵局.

本文梳理了IOS關於內管管理的相關知識點,只是列舉了部分,用作大家學習交流.做好記憶體管理,要主動學習,並在實踐中積累,多去研究一些記憶體優化方案,利用runtime去探究記憶體相關的底層實現.