iOS經典面試題總結--內存管理

iOS經典面試題總結--內存管理

內存管理面試

1.什麼是ARC?編程

ARC是automatic reference counting自動引用計數,在程序編譯時自動加入retain/release。在對象被建立時retain count+1,在對象被release時count-1,當count=0時,銷燬對象。程序中加入autoreleasepool對象會由系統自動加上autorelease方法,若是該對象引用計數爲0,則銷燬。那麼ARC是爲了解決MRC手動管理內存存在的一些而誕生的。多線程

MRC下內存管理的缺點:模塊化

  • 釋放一個堆內存時,首先要肯定指向這個堆空間的指針都被release了。(避免提早釋放)oop

  • 釋放指針指向的堆空間,首先要肯定哪些指向同一個堆,這些指針只能釋放一次。(避免釋放屢次,形成內存泄露)atom

  • 模塊化操做時,對象可能被多個模塊建立和使用,不能肯定最後由誰釋放spa

  • 多線程操做時,不肯定哪一個線程最後使用完畢。.net

雖然ARC給咱們編程帶來的不少好多,但也可能出現內存泄露。以下面兩種狀況:線程

  • 循環參照:A有個屬性參照B,B有個屬性參照A,若是都是strong參照的話,兩個對象都沒法釋放。scala

  • 死循環:若是有個ViewController中有無限循環,也會致使即便ViewController對應的view消失了,ViewController也不能釋放。

2.block通常用那個關鍵字修飾,爲何?

block通常使用copy關鍵之進行修飾,block使用copy是從MRC遺留下來的「傳統」,在MRC中,方法內容的block是在棧區的,使用copy能夠把它放到堆區。但在ARC中寫不寫都行:編譯器自動對block進行了copy操做。

3.用@property聲明的NSString(或NSArray,NSDictionary)常用copy關鍵字,爲何?若是改用strong關鍵字,可能形成什麼問題?

答:用@property聲明 NSString、NSArray、NSDictionary 常用copy關鍵字,是由於他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進行賦值操做,爲確保對象中的字符串值不會無心間變更,應該在設置新屬性值時拷貝一份。

若是咱們使用是strong,那麼這個屬性就有可能指向一個可變對象,若是這個可變對象在外部被修改了,那麼會影響該屬性。

copy此特質所表達的所屬關係與strong相似。然而設置方法並不保留新值,而是將其「拷貝」 (copy)。 當屬性類型爲NSString時,常常用此特質來保護其封裝性,由於傳遞給設置方法的新值有可能指向一個NSMutableString類的實例。這個類是NSString的子類,表示一種可修改其值的字符串,此時如果不拷貝字符串,那麼設置完屬性以後,字符串的值就可能會在對象不知情的狀況下遭人更改。因此,這時就要拷貝一份「不可變」 (immutable)的字符串,確保對象中的字符串值不會無心間變更。只要實現屬性所用的對象是「可變的」 (mutable),就應該在設置新屬性值時拷貝一份。

4.runloop、autorelease pool以及線程之間的關係。

每一個線程(包含主線程)都有一個Runloop。對於每個Runloop,系統會隱式建立一個Autorelease pool,這樣全部的release pool會構成一個像callstack同樣的一個棧式結構,在每個Runloop結束時,當前棧頂的Autorelease pool會被銷燬,這樣這個pool裏的每一個Object會被release。

5.@property 的本質是什麼?ivar、getter、setter 是如何生成並添加到這個類中的。

「屬性」(property)有兩大概念:ivar(實例變量)、存取方法(access method=getter),即@property = ivar + getter + setter。

例以下面的這個類:

1
2
3
4
@interface WBTextView :UITextView  
@property (nonatomic,copy)NSString *placehold;  
@property (nonatomic,copy)UIColor *placeholdColor;  
@end

類完成屬性的定之後,編譯器會自動編寫訪問這些屬性的方法(自動合成autosynthesis),上述代碼寫出來的類等效與下面的代碼:

1
2
3
4
5
6
@interface WBTextView :UITextView  
- (NSString *)placehold;  
-(void)setPlacehold:(NSString *)placehold;  
-(UIColor *)placeholdColor;  
-(void)setPlaceholdColor:(UIColor *)placeholdColor;  
@end

詳細介紹見:http://blog.csdn.net/jasonjwl/article/details/49427377

6.分別寫一個setter方法用於完成@property (nonatomic,retain)NSString *name和@property (nonatomic,copy) NSString *name

retain屬性的setter方法是保留新值並釋放舊值,而後更新實例變量,令其指向新值。順序很重要。假如還未保留新值就先把舊值釋放了,並且兩個值又指向同一個對象,先執行的release操做就可能致使系統將此對象永久回收。

1
2
3
4
5
6
7
8
9
10
11
12
-(void)setName:(NSString *)name
{
     [name retain];
     [_name release];
     _name = name;
}
-(void)setName:(NSString *)name
{
     
     [_name release];
     _name = [name copy];
}

7.說說assign vs weak,_block vs _weak的區別

assign適用於基本數據類型,weak是適用於NSObject對象,而且是一個弱引用。

assign其實頁能夠用來修飾對象,那麼爲何不用它呢?由於被assign修飾的對象在釋放以後,指針的地址仍是存在的,也就是說指針並無被置爲nil。若是在後續內存分配中,剛纔分到了這塊地址,程序就會崩潰掉。而weak修飾的對象在釋放以後,指針地址會被置爲nil。

_block是用來修飾一個變量,這個變量就能夠在block中被修改。

_block:使用_block修飾的變量在block代碼塊中會被retain(ARC下,MRC下不會retain)

_weak:使用_weak修飾的變量不會在block代碼塊中被retain

8.請說出下面代碼是否有問題,若是有問題請修改?

1
2
3
4
5
6
@autoreleasepool {
         for  (int i=0; i[largeNumber; i++) { (因識別問題,該行代碼中尖括號改成方括號代替)
             Person *per = [[Person alloc] init];
             [per autorelease];
         }
     }

內存管理的原則:若是對一個對象使用了alloc、copy、retain,那麼你必須使用相應的release或者autorelease。咋一看,這道題目有alloc,也有autorelease,二者對應起來,應該沒問題。但autorelease雖然會使引用計數減一,可是它並非當即減一,它的本質功能只是把對象放到離他最近的自動釋放池裏。當自動釋放池銷燬了,纔會向自動釋放池中的每個對象發送release消息。這道題的問題就在autorelease。由於largeNumber是一個很大的數,autorelease又不能使引用計數當即減一,因此在循環結束前會形成內存溢出的問題。

解決方案以下:

1
2
3
4
5
6
7
8
@autoreleasepool {
         for  (int i=0; i[100000; i++) { (因識別問題,該行代碼中尖括號改成方括號代替)
             @autoreleasepool {
             Person *per = [[Person alloc] init];
             [per autorelease];
         }
       }
     }

在循環內部再加一個自動釋放池,這樣就能保證每建立一個對象就能及時釋放。

9.請問下面代碼是否有問題,若有問題請修改?

1
2
3
4
5
6
7
8
9
@autoreleasepool {
         NSString *str = [[NSString alloc] init];
         [str retain];
         [str retain];
         str = @ "jxl" ;
         [str release];
         [str release];
         [str release];
}

這道題跟第8題同樣存在內存泄露問題,1.內存泄露 2.指向常量區的對象不能release。

指針變量str本來指向一塊開闢的堆區空間,可是通過從新給str賦值,str的指向發生了變化,由原來指向堆區空間,到指向常量區。常量區的變量根本不須要釋放,這就致使了原來開闢的堆區空間沒有釋放,照成內存泄露。

10.什麼狀況下使用weak關鍵字,相比assign有什麼不一樣?什麼狀況使用weak關鍵字?

  • 在ARC中,在有可能出現循環引用的時候,每每要經過讓其中一端使用weak來解決。好比delegate代理

  • 自身已經對它進行一次強引用,沒有必要再強引用一次,此時也會使用weak,自定義控件屬性通常也使用weak。

不一樣點:

  • weak此特質代表該屬性定義了一種「非擁有關係」。爲這種屬性設置新值時,設置方法既不保留新值,也不釋放舊值。此特性與assign同樣,然而在屬性所指的對象遭到推毀時,屬性值也會清空。而assign的「設置方法」只會執行鍼對「純量類型」 (scalar type,例如 CGFloat 或 NSlnteger 等)的簡單賦值操做。

  • assign能夠用非OC對象,而weak必須用於OC對象。

11.內存管理語義(assign、strong、weak等的區別)

  • assign 「設置方法」 只會執行鍼對「純量」的簡單賦值操做。

  • strong  此特質代表該屬性定義了一種「擁有關係」。爲這種屬性設置新值時,設置方法會先保留新值,並釋放舊值,而後再將新值設置上去。

  • weak 此特質代表該屬性定義了一種「非擁有關係」。爲這種屬性設置新值時,設置方法既不保留新值,也不釋放舊值。此特質同assign相似,然而在屬性所指的對象遭到推毀時,屬性值也會清空。

  • unsafe_unretained  此特質的語義和assign相同,可是它適用於「對象類型」,該特質表達一種「非擁有關係」,當目標對象遭到推毀時,屬性值不會自動清空,這一點與weak有區別。

  • copy 此特質所表達的所屬關係與strong相似。然而設置方法並不保留新值,而是設置方法並不保留新值,而是將其「拷貝」。當屬性類型爲NSString*時,常常用此特質來保護其封裝性,由於傳遞給設置方法的新值有可能指向一個NSMutableString類的實例。這個類是NSString的子類,表示一種能夠修改其值的字符串,此時如果不拷貝字符串,那麼設置完屬性以後,字符串的值就可能會在對象不知情的狀況下遭人更改。因此,這時就要拷貝一份「不可變」的字符串,確保對象中的字符串值不會無心間變更。只要實現屬性所用的對象是「可變的」,就應該在設置新屬性值時拷貝一份。

後續會繼續增長內存管理方面的內容以及多線程等內容,持續更新中....,敬請期待!

相關文章
相關標籤/搜索