11.看下面的程序,第一個NSLog會輸出什么?這時str的retainCount是多少?第二個和第三個呢? 為什么?
NSMutableArray* ary = [NSMutableArray array];
NSString *str = [NSString stringWithFormat:@"test"];
[str retain];
[ary addObject:str];
NSLog(@"%@%ld",str,(unsigned long)[str retainCount]);
[str retain];
[str release];
[str release];
NSLog(@"%@%ld",str,(unsigned long)[str retainCount]);
[ary removeAllObjects];
NSLog(@"%@%ld",str,(unsigned long)[str retainCount]);
答:
str的retainCount創(chuàng)建+1,retain+1,加入數(shù)組自動+1
3
retain+1,release-1,release-1
2
數(shù)組刪除所有對象,所有數(shù)組內(nèi)的對象自動-1
1
9.內(nèi)存管理的幾條原則時什么?按照默認(rèn)法則.哪些關(guān)鍵字生成的對象需要手動釋放?在和property結(jié)合的時候怎樣有效的避免內(nèi)存泄露?
誰創(chuàng)建,誰釋放
誰retain,誰release
除alloc、new或copy之外的方法創(chuàng)建的對象都被聲明了autorelease
關(guān)鍵字alloc 或new 生成的對象需要手動釋放;
設(shè)置正確的property屬性,對于retain需要在合適的地方釋放。
8.Objective-C如何對內(nèi)存管理的,說說你的看法和解決方法?
1、自動釋放池:可以簡化內(nèi)存管理代碼,系統(tǒng)會自動釋放池中的對象,但系統(tǒng)并不是立即釋放池中的對象,而是在一個run loop之后才釋放。
2、手動內(nèi)存計數(shù):當(dāng)我們對對象進(jìn)行了alloc、retain、copy或new操作后,我們擁有了對象的控制權(quán),因此需要對其進(jìn)行release,當(dāng)計數(shù)器到0的時候,系統(tǒng)會自動調(diào)用alloc方法來釋放內(nèi)存中的對象。
3、ARC自動內(nèi)存計數(shù):使用了同樣的引用計數(shù)機(jī)制,不需要手動添加的用來處理內(nèi)存管理的代碼可以自動地由編譯器完成。
3、objc如何管理內(nèi)存
1).MRC(manual retain-release)手動內(nèi)存管理
2).ARC(automatic reference counting)自動引用計數(shù)
3).Garbage collection (垃圾回收)
但是iOS不支持垃圾回收, ARC作為LLVM(編譯器的架構(gòu)系統(tǒng),用c++編寫而成的) 3.0編譯器的一項特性, 在iOS5.0 (Xcode4) 版本后推出的自動內(nèi)存管理, 蘋果推薦使用ARC技術(shù)來管理內(nèi)存, 節(jié)約時間 , 提高效率 , 減少代碼量 , 降低出錯幾率. 開發(fā)者不需要再手動寫入retain,release,autorelease三個關(guān)鍵字,手動管理內(nèi)存, 編譯器將自動在代碼合適的地方插入retain,release,autorelease進(jìn)行內(nèi)存管理.ARC的判斷準(zhǔn)則, 只要沒有強(qiáng)指針指向?qū)ο? 對象就會被釋放.
10、autorelease的對象是在什么時候被release的?
對象是引用計數(shù)為0時被release。
autorelease實際上只是把對release的調(diào)用延遲了,對于每一個Autorelease,系統(tǒng)只是把該Object放入了當(dāng)前的Autorelease pool中,當(dāng)該pool被釋放時,該pool中的所有Object會被調(diào)用Release。對于每一個Runloop, 系統(tǒng)會隱式創(chuàng)建一個Autorelease pool,這樣所有的release pool會構(gòu)成一個象CallStack一樣的一個棧式結(jié)構(gòu),在每一個Runloop結(jié)束時,當(dāng)前棧頂?shù)腁utorelease pool會被銷毀,這樣這個pool里的每個Object(就是autorelease的對象)會被release。那什么是一個Runloop呢? 一個UI事件,Timer call, delegate call, 都會是一個新的Runloop。
autorelease和release的區(qū)別
1.如果能夠真正的理解autorelease,那么才是理解了Objective
c的內(nèi)存管理。Autorelease實際上只是把對release的調(diào)用延遲了,對于每一個Autorelease,系統(tǒng)只是把該Object放入了當(dāng)前的Autorelease pool中,當(dāng)該pool被釋放時,該pool中的所有Object會被調(diào)用Release。
實際上對于 [NSString stringWithFormat:1.0] 這類構(gòu)造函數(shù)返回的對象都是autorelease的。
2. autorelease pool來避免頻繁申請/釋放內(nèi)存(就是pool的作用了)。這個應(yīng)該是相對比較好理解的。
總結(jié):
(1)一定要注意Autorelease pool的生存周期,理解Runloop,避免在對象被釋放后使用。
(2)[NSString stringWithFormat]這類函數(shù)返回的對象是不需要再自己release的,它已經(jīng)被autorelease了, 如果你想把它當(dāng)一個全局對象使用,那必須自己再retain, 釋放時再release。
為什么需要Auto release ?
這個auto release有什么好,象C/C++那樣,自己申請,自己釋放,完全可控不好么,這個auto relase完全不可控,你都不知到它什么時候會被真正的release。我的理解它有一個作用就是可以做到每個函數(shù)對自己申請的對象負(fù)責(zé),自己申請,自己釋放,該函數(shù)的調(diào)用者不需要關(guān)心它內(nèi)部申請對象的管理。 在下面這個例子中,F(xiàn)unc1的調(diào)用者不需要再去關(guān)心obj的釋放。
ClassA *Func1()
{
ClassA *obj = [[[ClassA alloc]init]autorelease];
return obj;
}
(1)在Iphone項目中,大家會看到一個默認(rèn)的Autorelease pool,程序開始時創(chuàng)建,程序退出時銷毀,按照對Autorelease的理解,豈不是所有autorelease pool里的對象在程序退出時才release, 這樣跟內(nèi)存泄露有什么區(qū)別?
答案是,對于每一個Runloop, 系統(tǒng)會隱式創(chuàng)建一個Autorelease pool,這樣所有的release pool會構(gòu)成一個象CallStack一樣的一個棧式結(jié)構(gòu),在每一個Runloop結(jié)束時,當(dāng)前棧頂?shù)腁utorelease pool會被銷毀,這樣這個pool里的每個Object會被release。
那什么是一個Runloop呢? 一個UI事件,Timer call, delegate call, 都會是一個新的Runloop。例子如下:
NSString* globalObject;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
globalObject = [[NSString alloc] initWithFormat:@"Test"];
NSLog(@"Retain count after create: %d", [globalObject retainCount]); // output 1.
[globalObject retain];
NSLog(@"Retain count after retain: %d", [globalObject retainCount]); // output 2.
}
- (void)applicationWillTerminate:(UIApplication *)application {
NSLog(@"Retain count after Button click runloop finished: %d", [globalObject retainCount]);
// 輸出1. Button click loop finished, it's autorelease pool released, globalObject get released once.
}
-(IBAction)onButtonClicked {
[globalObject autorelease];
NSLog(@"Retain count after autorelease: %d", [globalObject retainCount]);
// 輸出2。 Autorelease被call, globalObject被加如當(dāng)前的AutoreleaePool。
}
Cocoa的內(nèi)存管理分為 索引計數(shù)法(Reference Counting/ Retain Count)和 垃圾收集法(Garbage Collection)。而iPhone上目前只支持前者,所以autorelease就成為很多人的“捷徑”。
但是!autorelease其實并不是“自動釋放”,不像垃圾收集法,對對象之間的關(guān)系偵測后發(fā)現(xiàn)垃圾-刪除。但是autorelease其實是“延后釋放”,在一個運(yùn)行周期后被標(biāo)記為autorelease會被釋放掉。
切記小心使用autorelease,理解autorelease,防止在你還需要該對象的時候已經(jīng)被系統(tǒng)釋放掉了 誤釋放對象
問題一:
value = [array objectAtIndex:n]; //得到一個數(shù)組中的對象
[arry removeObjectAtIndex:n]; //卸載那個對象因為value得到了那個對象,但是由于另外一個擁有者release了該對象,所以其實value現(xiàn)在成了搖擺指針(無效數(shù)據(jù))
問題二:
myArray = [NSArray array];
...
[myArray release];NSArray返回的是一個自動釋放對象,不僅myArray不應(yīng)該在一段時間后release,而應(yīng)該在適當(dāng)?shù)臅r候先retain,以防止該array被系統(tǒng)誤釋放。
問題三:
rocket = [rocketLauncher aRocket];
[rocketLauncher release];和array這種數(shù)據(jù)收集類對象一樣,如果我們得到了一個類的子對象而不retain它,那么在原父類被釋放的時候,這個rocket其實也會失去其意義。
4、以下每行代碼執(zhí)行后,person對象的retainCount分別是多少?請在每行語句右邊標(biāo)出。
1、Person *person = [[Person alloc] init]; 1
[person retain]; 2
[person autorelease]; 2
[person release]; 1
2、Person *person = [[Person alloc] init]; 1
[person retain]; 2
[person release]; 1
[person release]; 0
3、NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Person *person = [[Person alloc] init]; 1
[person autorelease]; 1
[pool release]; 0
1、內(nèi)存優(yōu)化
iOS優(yōu)化(一)內(nèi)存優(yōu)化經(jīng)驗:http://www.jianshu.com/p/ef52250df748
ios-01-內(nèi)存優(yōu)化整理:http://www.jianshu.com/p/ba3e159f7743
內(nèi)存管理的原則:凡是操作他的函數(shù)中出現(xiàn)了"create,copy,retaion" 都必須有一個 函數(shù)中包含"release"的方法與之對應(yīng)
163.自動釋放池是什么,如何工作?
一、什么是自動釋放池
1、Autorelease pool
自動釋放池(Autorelease pool)是OC的一種內(nèi)存自動回收機(jī)制,可以將一些臨時變量通過自動釋放池來回收統(tǒng)一釋放
自動釋放池本身銷毀的時候,池子里面所有的對象都會做一次release操作
2、autorelease
任何OC對象只要調(diào)用autorelease方法,就會把該對象放到離自己最近的自動釋放池中(棧頂?shù)尼尫懦兀?/p>二:O-C當(dāng)中的內(nèi)存釋放,并不是像java/.net那樣有一個自動的釋放池,開發(fā)人員不用去關(guān)心有關(guān)內(nèi)存釋放的問題,O-C里面的自動釋放池比c語言的手動內(nèi)存管理要好一些,但是相對于java/.net來說又弱一些,所以說O-C當(dāng)中的釋放屬于半自動的釋放池。
三、如何創(chuàng)建一個自動釋放池
//ios5.0新方式
@autoreleasepool {
}
//ios5.0之前的老方式
NSAutoreleasePool *pool=[[NSAutoreleasePoolalloc]init];
[pool release];四、自動釋放池如何釋放對象內(nèi)存
黃金法則:如果對一個對象使用了alloc,[mutable]copy,retain,那么必須使用相應(yīng)的release或者autorelease。
17.下面關(guān)于Objective-C內(nèi)存管理的描述錯誤的是(A )
A.當(dāng)使用ARC來管理內(nèi)存時,對象的retain,dealloc方法不會被調(diào)用
B.autoreleasepool在drain的時候會釋放在其中分配的對象
C.當(dāng)使用ARC來管理內(nèi)存時,在線程中大量分配對象而不用autoreleasepool則可能會造成內(nèi)存泄露
D.在使用ARC的項目中不能使用NSZone
101.iOS有垃圾回收機(jī)制嗎?它是以怎樣的機(jī)制來工作的?
答: OC是支持垃圾回收機(jī)制的(Garbage collection簡稱GC),但是apple的移動終端中,是不支持GC的,Mac桌面系統(tǒng)開發(fā)中是支持的。
移動終端開發(fā)是支持ARC(Automatic Reference Counting的簡稱),ARC是在IOS5之后推出的新技術(shù),它與GC的機(jī)制是不同的。我們在編寫代碼時,不需要向?qū)ο蟀l(fā)送release或者autorelease方法,也不可以調(diào)用delloc方法,編譯器會在合適的位置自動給用戶生成release消息(autorelease),ARC的特點(diǎn)是自動引用技術(shù)簡化了內(nèi)存管理的難度.
63.自動釋放池底層怎么實現(xiàn)?
答:自動釋放池以棧的形式實現(xiàn):當(dāng)你創(chuàng)建一個新的自動釋放池時,它將被添加到棧頂。當(dāng)一個對象收到發(fā)送autorelease消息時,他被添加到當(dāng)前線程的處于棧頂?shù)淖詣俞尫懦刂校?dāng)自動釋放池被回收時,他們從棧中被刪除,并且會給池子里面所有的對象都會做一次release操作。
65.簡單描述一下客戶端的緩存機(jī)制?
答案:無法簡述,詳細(xì)了解下,明白了夠裝逼就好http://www.cnblogs.com/wendingding/p/3950198.html
1、內(nèi)存中的棧和堆的區(qū)別是什么?那些數(shù)據(jù)在棧上,哪些在堆上?
棧:編譯器自動分配釋放,存放函數(shù)的參數(shù)值,局部變量的值。
堆:由程序猿管理釋放,存放靜態(tài)變量,字符常量,資源,編譯運(yùn)行時的數(shù)據(jù)。
1.內(nèi)存中的棧和堆得區(qū)別是什么?哪些數(shù)據(jù)在棧上?哪些在堆上?
一、堆棧空間分配區(qū)別:
1、棧(操作系統(tǒng)):由操作系統(tǒng)自動分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧;
2、堆(操作系統(tǒng)): 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時可能由OS回收,分配方式倒是類似于鏈表。二、堆棧緩存方式區(qū)別:
1、棧使用的是一級緩存, 他們通常都是被調(diào)用時處于存儲空間中,調(diào)用完畢立即釋放;
2、堆是存放在二級緩存中,生命周期由虛擬機(jī)的垃圾回收算法來決定(并不是一旦成為孤兒對象就能被回收)。所以調(diào)用這些對象的速度要相對來得低一些。三、堆棧數(shù)據(jù)結(jié)構(gòu)區(qū)別:
堆(數(shù)據(jù)結(jié)構(gòu)):堆可以被看成是一棵樹,如:堆排序;
棧(數(shù)據(jù)結(jié)構(gòu)):一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu)。棧空間中一般存儲基本類型,對象的地址
堆空間一般存放對象本身,block的copy等。
182.堆和棧的區(qū)別?
答:答:棧完全是由系統(tǒng)管理的,堆是由程序員自己控制管理的,包括內(nèi)存空間的開辟和釋放.棧是先進(jìn)后出.
315、Objective-C堆和棧的區(qū)別?
答:
1、管理方式:
對于棧來講,是由編譯器自動管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。2、申請大小:
棧:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數(shù)),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。
3、碎片問題:
對于堆來講,頻繁的new/delete勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進(jìn)后出的隊列,他們是如此的一一對應(yīng),以至于永遠(yuǎn)都不可能有一個內(nèi)存塊從棧中間彈出4、分配方式:
堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動態(tài)分配由alloca函數(shù)進(jìn)行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進(jìn)行釋放,無需我們手工實現(xiàn)。5、分配效率:
棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計算機(jī)會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。堆則是C/C++函數(shù)庫提供的,它的機(jī)制是很復(fù)雜的。
9.簡單闡述堆和棧的區(qū)別
棧:
在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。
堆:
就是那些由new分配的內(nèi)存塊,他們的釋放編譯器不去管,由我們的應(yīng)用程序去控制,一般一個new就要對應(yīng)一個delete。如果程序員沒有釋放掉,那么在程序結(jié)束后,操作系統(tǒng)會自動回收。堆和棧主要的區(qū)別有以下幾點(diǎn):
1、管理方式不同;
2、空間大小不同;
3、能否產(chǎn)生碎片不同;
4、生長方向不同;
5、分配方式不同;
6、分配效率不同;1、管理方式:
對于棧來講,是由編譯器自動管理,無需我們手工控制;
對于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。2、空間大小:
一般來講在32位系統(tǒng)下,堆內(nèi)存可以達(dá)到4G的空間,從這個角度來看堆內(nèi)存幾乎是沒有什么限制的。但是對于棧來講,一般都是有一定的空間大小的,例如,在VC6下面,默認(rèn)的棧空間大小是1M(好像是,記不清楚了)。
當(dāng)然,我們可以修改:
打開工程,依次操作菜單如下:Project->Setting->Link,在Category 中選中Output,然后在Reserve中設(shè)定堆棧的最大值和commit。
注意:reserve最小值為4Byte;commit是保留在虛擬內(nèi)存的頁文件里面,它設(shè)置的較大會使棧開辟較大的值,可能增加內(nèi)存的開銷和啟動時間。3、碎片問題:
對于堆來講,頻繁的new/delete勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。
對于棧來講,則不會存在這個問題,因為棧是先進(jìn)后出的隊列,他們是如此的一一對應(yīng),以至于永遠(yuǎn)都不可能有一個內(nèi)存塊從棧中間彈出,在他彈出之前,在他上面的后進(jìn)的棧內(nèi)容已經(jīng)被彈出,詳細(xì)的可以參考數(shù)據(jù)結(jié)構(gòu),這里我們就不再一一討論了。4、生長方向:
對于堆來講,生長方向是向上的,也就是向著內(nèi)存地址增加的方向;
對于棧來講,它的生長方向是向下的,是向著內(nèi)存地址減小的方向增長。5、分配方式:
堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。
棧有2種分配方式:靜態(tài)分配和動態(tài)分配。
*靜態(tài)分配是編譯器完成的,比如局部變量的分配。
*動態(tài)分配由alloca函數(shù)進(jìn)行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進(jìn)行釋放,無需我們手工實現(xiàn)。6、分配效率:
棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計算機(jī)會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。
堆則是C/C++函數(shù)庫提供的,它的機(jī)制是很復(fù)雜的,例如為了分配一塊內(nèi)存,庫函數(shù)會按照一定的算法(具體的算法可以參考數(shù)據(jù)結(jié)構(gòu)/操作系統(tǒng))在堆內(nèi)存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內(nèi)存碎片太多),就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機(jī)會分到足夠大小的內(nèi)存,然后進(jìn)行返回。顯然,堆的效率比棧要低得多。從這里我們可以看到,堆和棧相比,由于大量new/delete的使用,容易造成大量的內(nèi)存碎片;由于沒有專門的系統(tǒng)支持,效率很低;由于可能引發(fā)用戶態(tài)和核心態(tài)的切換,內(nèi)存的申請,代價變得更加昂貴。所以棧在程序中是應(yīng)用最廣泛的,就算是函數(shù)的調(diào)用也利用棧去完成,函數(shù)調(diào)用過程中的參數(shù),返回地址,EBP和局部變量都采用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆。
雖然棧有如此眾多的好處,但是由于和堆相比不是那么靈活,有時候分配大量的內(nèi)存空間,還是用堆好一些。
無論是堆還是棧,都要防止越界現(xiàn)象的發(fā)生(除非你是故意使其越界),因為越界的結(jié)果要么是程序崩潰,要么是摧毀程序的堆、棧結(jié)構(gòu),產(chǎn)生意想不到的結(jié)果,就算是在你的程序運(yùn)行過程中,沒有發(fā)生上面的問題,你還是要小心,說不定什么時候就崩掉,那時候debug可是相當(dāng)困難的。
1、程序在內(nèi)存中運(yùn)行時,內(nèi)存分幾個區(qū)?各自用途?
答:
棧區(qū):由編譯器自動分配釋放存放函數(shù)的參數(shù)值,局部變量的值等。在高級語言中不需要顯式的分配和釋放
堆區(qū):一般由程序員手動分配釋放,如果不釋放可有由系統(tǒng)釋放。
數(shù)據(jù)區(qū):存儲全局和靜態(tài)變量。初始化的全局和靜態(tài)變量在一塊區(qū)域,未初始化的放在相鄰的一塊區(qū)域,程序結(jié)束后由系統(tǒng)釋放。
代碼區(qū):存放函數(shù)體的二進(jìn)制代碼。
1、什么情況下會出現(xiàn)內(nèi)存的循環(huán)引用
1.NSTimer-他的target是self的時候,要手動停止定時器
2.Block-retain circle
3.delegate
320、autorelease和垃圾回收機(jī)制(gc)有什么關(guān)系?
答:autorelease只是延遲釋放,gc是每隔一段時間詢問程序,看是否有無指針指向的對象,若有,就將它回收。他們兩者沒有什么關(guān)系。
184.自動釋放池是什么,如何工作?
答:當(dāng)向一個對象發(fā)送一個autorelease消息時,Cocoa就會將該對象的一個引用放入到最新的自動釋放池。它仍然是個正當(dāng)?shù)膶ο螅虼俗詣俞尫懦囟x的作用域內(nèi)的其它對象可以向它發(fā)送消息。當(dāng)程序執(zhí)行到作用域結(jié)束的位置時,自動釋放池就會被釋放,池中的所有對象也就被釋放。
177.隊列和棧有什么區(qū)別。
棧(Stack):是限定只能在表的一端進(jìn)行插入和刪除操作的線性表。
隊列(Queue):是限定只能在表的一段進(jìn)行插入和在另一端進(jìn)行刪除操作的的線性表。
隊列和棧的區(qū)別:
1)、隊列是先進(jìn)先出,棧是先進(jìn)后出
2)、遍歷數(shù)據(jù)速度不同,隊列遍歷速度要快得多
44.你在開發(fā)大型項目時,如何進(jìn)行內(nèi)存泄露檢測的?
可以通過xcode的自帶工具run---start with performance tool里有instruments下有個leaks工具,
啟動此工具后,運(yùn)行項目,工具里可以顯示內(nèi)存泄露的情況,雙擊可找到源碼位置,可以幫助進(jìn)行內(nèi)存泄露的處理。
11 、類方法創(chuàng)造的對象要不要用release釋放?
答:任何方法創(chuàng)建的對象對遵從內(nèi)存管理原則,用alloc方法分配的對象就需要釋放,如果用類方法創(chuàng)建對象時候,沒有用到alloc,那么分配空間的問題,已經(jīng)在方法內(nèi)部做了處理,所以我們就不需要去釋放了。
17、下面關(guān)于Objective-C內(nèi)存管理的描述錯誤的是
A. 當(dāng)使用ARC來管理內(nèi)存時,代碼中不可以出現(xiàn)autorelease
B. autoreleasepool 在 drain 的時候會釋放在其中分配的對象
C. 當(dāng)使用ARC來管理內(nèi)存時,在線程中大量分配對象而不用autoreleasepool則可能會造成內(nèi)存泄露
D. 在使用ARC的項目中不能使用NSZone
(A)
10。 內(nèi)存管理理解不正確的是 B
A 程序A里有一段內(nèi)存被成功申請完成之后,內(nèi)存計數(shù)器就從0變?yōu)? (這個過程是alloc);
B 程序B里要使用已存在內(nèi)存,那么內(nèi)存計數(shù)器從1變?yōu)? (這個過程是retain或者copy);
C 緊接著程序A不需要這個內(nèi)存了,那么程序A就把這個內(nèi)存計數(shù)器減1 (這個過程是release);
D 當(dāng)系統(tǒng)發(fā)現(xiàn)這個內(nèi)存計數(shù)器變?yōu)樾∮诘扔?,那么就調(diào)用垃圾回收程序把這段內(nèi)存回收(這個過程是dealloc);
313、談?wù)凮bject-C的內(nèi)存管理方式及過程?
從一段內(nèi)存被申請之后,就存在一個變量用于保存這段內(nèi)存被使用的次數(shù),我們暫時把它稱為計數(shù)器,當(dāng)計數(shù)器變?yōu)?的時候,那么就是釋放這段內(nèi)存的時候,比如說,當(dāng)在程序A里面一段內(nèi)存被成功申請完成之后,那么這個計數(shù)器就從0變成了1(我們把這個過程叫做alloc),然后程序B也需要使用這個內(nèi)存,那么計數(shù)器就從1變成了2(我們把這個過程叫做retain),緊接著程序A不再需要這段內(nèi)存了,那么程序A就把這個計數(shù)器減1(我們把這個過程叫做release),程序B也不再需要這段內(nèi)存的時候,那么也把計數(shù)器減1(這個過程還是release),當(dāng)系統(tǒng)(也就是Foundation)發(fā)現(xiàn)這個計數(shù)器變成了0,那么就會調(diào)用內(nèi)存回收程序把這段內(nèi)存回收(我們把這個過程叫做dealloc)。
201.內(nèi)存管理的幾條原則是什么?按照默認(rèn)法則,哪些關(guān)鍵字生成的對象需要手動釋放,在和property結(jié)合的時候怎樣有效的避免內(nèi)存泄露?
答:當(dāng)使用new、alloc或copy方法創(chuàng)建一個對象時,該對象引用計數(shù)器為1。如果不需要使用該對象,可以向其發(fā)送release或autorelease消息,在其使用完畢時被銷毀。
如果通過其他方法獲取一個對象,則可以假設(shè)這個對象引用計數(shù)為1,并且被設(shè)置為autorelease,不需要對該對象進(jìn)行清理,如果確實需要retain這個對象,則需要使用完畢后release。
如果retain了某個對象,需要release或autorelease該對象,保持retain方法和release方法使用次數(shù)相等。
使用new、alloc、copy關(guān)鍵字生成的對象和retain了的對象需要手動釋放。設(shè)置為autorelease的對象不需要手動釋放,會直接進(jìn)入自動釋放池。
171.什么是ARC?請簡述一下ARC的原理。
1)ARC是iOS 5推出的新功能,全稱叫ARC(Automatic Reference Counting)。簡單地說,就是代碼中自動加入了retain/release,原先需要手動添加的用來處理內(nèi)存管理的引用計數(shù)的代碼可以自動地由編譯器完成了。
2)ARC的規(guī)則就是只要對象沒有強(qiáng)指針引用,就會被釋放掉,換而言之只要還有一個強(qiáng)引用指針變量指向?qū)ο螅敲催@個對象就會存在內(nèi)存中。弱指針指向的對象,會被自動變成空指針(nil指針),從而不會引發(fā)野指針錯誤。
7.說說assign vs weak,_block vs _weak的區(qū)別
assign適用于基本數(shù)據(jù)類型,weak是適用于NSObject對象,并且是一個弱引用。
assign其實頁可以用來修飾對象,那么為什么不用它呢?因為被assign修飾的對象在釋放之后,指針的地址還是存在的,也就是說指針并沒有被置為nil。如果在后續(xù)內(nèi)存分配中,剛才分到了這塊地址,程序就會崩潰掉。而weak修飾的對象在釋放之后,指針地址會被置為nil。
_block是用來修飾一個變量,這個變量就可以在block中被修改。
_block:使用_block修飾的變量在block代碼塊中會被retain(ARC下,MRC下不會retain)
_weak:使用_weak修飾的變量不會在block代碼塊中被retain
8.請說出下面代碼是否有問題,如果有問題請修改?
@autoreleasepool {
for (int i=0; i<largeNumber; i++) {
Person *per = [[Person alloc] init];
[per autorelease];
}
}
內(nèi)存管理的原則:如果對一個對象使用了alloc、copy、retain,那么你必須使用相應(yīng)的release或者autorelease。咋一看,這道題目有alloc,也有autorelease,兩者對應(yīng)起來,應(yīng)該沒問題。但autorelease雖然會使引用計數(shù)減一,但是它并不是立即減一,它的本質(zhì)功能只是把對象放到離他最近的自動釋放池里。當(dāng)自動釋放池銷毀了,才會向自動釋放池中的每一個對象發(fā)送release消息。這道題的問題就在autorelease。因為largeNumber是一個很大的數(shù),autorelease又不能使引用計數(shù)立即減一,所以在循環(huán)結(jié)束前會造成內(nèi)存溢出的問題。
解決方案如下:
@autoreleasepool {
for (int i=0; i<100000; i++) {
@autoreleasepool {
Person *per = [[Person alloc] init];
[per autorelease];
}
}
}
在循環(huán)內(nèi)部再加一個自動釋放池,這樣就能保證每創(chuàng)建一個對象就能及時釋放。
9.請問下面代碼是否有問題,如有問題請修改?
@autoreleasepool {
NSString *str = [[NSString alloc] init];
[str retain];
[str retain];
str = @"jxl";
[str release];
[str release];
[str release];
}
這道題跟第8題一樣存在內(nèi)存泄露問題,1.內(nèi)存泄露 2.指向常量區(qū)的對象不能release。
指針變量str原本指向一塊開辟的堆區(qū)空間,但是經(jīng)過重新給str賦值,str的指向發(fā)生了變化,由原來指向堆區(qū)空間,到指向常量區(qū)。常量區(qū)的變量根本不需要釋放,這就導(dǎo)致了原來開辟的堆區(qū)空間沒有釋放,造成內(nèi)存泄露。
10.什么情況下使用weak關(guān)鍵字,相比assign有什么不同?什么情況使用weak關(guān)鍵字?
在ARC中,在有可能出現(xiàn)循環(huán)引用的時候,往往要通過讓其中一端使用weak來解決。比如delegate代理。
自身已經(jīng)對它進(jìn)行一次強(qiáng)引用,沒有必要再強(qiáng)引用一次,此時也會使用weak,自定義控件屬性一般也使用weak。
不同點(diǎn):
weak此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系”。為這種屬性設(shè)置新值時,設(shè)置方法既不保留新值,也不釋放舊值。此特性與assign一樣,然而在屬性所指的對象遭到推毀時,屬性值也會清空。而assign的“設(shè)置方法”只會執(zhí)行針對“純量類型” (scalar type,例如 CGFloat 或 NSlnteger 等)的簡單賦值操作。assign可以用非OC對象,而weak必須用于OC對象。
11.內(nèi)存管理語義(assign、strong、weak等的區(qū)別)
assign:“設(shè)置方法” 只會執(zhí)行針對“純量”的簡單賦值操作。
strong:此特質(zhì)表明該屬性定義了一種“擁有關(guān)系”。為這種屬性設(shè)置新值時,設(shè)置方法會先保留新值,并釋放舊值,然后再將新值設(shè)置上去。
weak:此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系”。為這種屬性設(shè)置新值時,設(shè)置方法既不保留新值,也不釋放舊值。此特質(zhì)同assign類似,然而在屬性所指的對象遭到推毀時,屬性值也會清空。
unsafe_unretained:此特質(zhì)的語義和assign相同,但是它適用于“對象類型”,該特質(zhì)表達(dá)一種“非擁有關(guān)系”,當(dāng)目標(biāo)對象遭到推毀時,屬性值不會自動清空,這一點(diǎn)與weak有區(qū)別。
copy:此特質(zhì)所表達(dá)的所屬關(guān)系與strong類似。然而設(shè)置方法并不保留新值,而是設(shè)置方法并不保留新值,而是將其“拷貝”。當(dāng)屬性類型為NSString*時,經(jīng)常用此特質(zhì)來保護(hù)其封裝性,因為傳遞給設(shè)置方法的新值有可能指向一個NSMutableString類的實例。這個類是NSString的子類,表示一種可以修改其值的字符串,此時若是不拷貝字符串,那么設(shè)置完屬性之后,字符串的值就可能會在對象不知情的情況下遭人更改。所以,這時就要拷貝一份“不可變”的字符串,確保對象中的字符串值不會無意間變動。只要實現(xiàn)屬性所用的對象是“可變的”,就應(yīng)該在設(shè)置新屬性值時拷貝一份。
1.什么是ARC?
ARC是automatic reference counting自動引用計數(shù),在程序編譯時自動加入retain/release。在對象被創(chuàng)建時retain count+1,在對象被release時count-1,當(dāng)count=0時,銷毀對象。程序中加入autoreleasepool對象會由系統(tǒng)自動加上autorelease方法,如果該對象引用計數(shù)為0,則銷毀。那么ARC是為了解決MRC手動管理內(nèi)存存在的一些而誕生的。
MRC下內(nèi)存管理的缺點(diǎn):
釋放一個堆內(nèi)存時,首先要確定指向這個堆空間的指針都被release了。(避免提前釋放)
釋放指針指向的堆空間,首先要確定哪些指向同一個堆,這些指針只能釋放一次。(避免釋放多次,造成內(nèi)存泄露)
模塊化操作時,對象可能被多個模塊創(chuàng)建和使用,不能確定最后由誰釋放。
多線程操作時,不確定哪個線程最后使用完畢。雖然ARC給我們編程帶來的很多好處,但也可能出現(xiàn)內(nèi)存泄露。如下面兩種情況:
循環(huán)參照:A有個屬性參照B,B有個屬性參照A,如果都是strong參照的話,兩個對象都無法釋放。
死循環(huán):如果有個ViewController中有無限循環(huán),也會導(dǎo)致即使ViewController對應(yīng)的view消失了,ViewController也不能釋放。
2.block一般用哪個關(guān)鍵字修飾,為什么?
block一般使用copy關(guān)鍵字進(jìn)行修飾,block使用copy是從MRC遺留下來的“傳統(tǒng)”,在MRC中,方法內(nèi)容的block是在棧區(qū)的,使用copy可以把它放到堆區(qū)。但在ARC中寫不寫都行:編譯器自動對block進(jìn)行了copy操作。
3.用@property聲明的NSString(或NSArray,NSDictionary)經(jīng)常使用copy關(guān)鍵字,為什么?如果改用strong關(guān)鍵字,可能造成什么問題?
答:用@property聲明 NSString、NSArray、NSDictionary 經(jīng)常使用copy關(guān)鍵字,是因為他們有對應(yīng)的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進(jìn)行賦值操作,為確保對象中的字符串值不會無意間變動,應(yīng)該在設(shè)置新屬性值時拷貝一份。
如果我們使用是strong,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性。
copy此特質(zhì)所表達(dá)的所屬關(guān)系與strong類似。然而設(shè)置方法并不保留新值,而是將其“拷貝” (copy)。 當(dāng)屬性類型為NSString時,經(jīng)常用此特質(zhì)來保護(hù)其封裝性,因為傳遞給設(shè)置方法的新值有可能指向一個NSMutableString類的實例。這個類是NSString的子類,表示一種可修改其值的字符串,此時若是不拷貝字符串,那么設(shè)置完屬性之后,字符串的值就可能會在對象不知情的情況下遭人更改。所以,這時就要拷貝一份“不可變” (immutable)的字符串,確保對象中的字符串值不會無意間變動。只要實現(xiàn)屬性所用的對象是“可變的” (mutable),就應(yīng)該在設(shè)置新屬性值時拷貝一份。
4.runloop、autorelease pool以及線程之間的關(guān)系。
每個線程(包含主線程)都有一個Runloop。對于每一個Runloop,系統(tǒng)會隱式創(chuàng)建一個Autorelease pool,這樣所有的release pool會構(gòu)成一個像callstack一樣的一個棧式結(jié)構(gòu),在每一個Runloop結(jié)束時,當(dāng)前棧頂?shù)腁utorelease pool會被銷毀,這樣這個pool里的每個Object會被release。
5.@property 的本質(zhì)是什么?ivar、getter、setter 是如何生成并添加到這個類中的。
“屬性”(property)有兩大概念:ivar(實例變量)、存取方法(access method=getter),即@property = ivar + getter + setter。
例如下面的這個類:
@interface WBTextView :UITextView
@property (nonatomic,copy)NSString *placehold;
@property (nonatomic,copy)UIColor *placeholdColor;
@end
類完成屬性的定以后,編譯器會自動編寫訪問這些屬性的方法(自動合成autosynthesis),上述代碼寫出來的類等效與下面的代碼:
@interface WBTextView :UITextView
- (NSString *)placehold;
-(void)setPlacehold:(NSString *)placehold;
-(UIColor *)placeholdColor;
-(void)setPlaceholdColor:(UIColor *)placeholdColor;
@end
詳細(xì)介紹見:http://blog.csdn.net/jasonjwl/article/details/49427377
6.分別寫一個setter方法用于完成
@property (nonatomic,retain)NSString *name
和
@property (nonatomic,copy) NSString *name
retain屬性的setter方法是保留新值并釋放舊值,然后更新實例變量,令其指向新值。順序很重要。假如還未保留新值就先把舊值釋放了,而且兩個值又指向同一個對象,先執(zhí)行的release操作就可能導(dǎo)致系統(tǒng)將此對象永久回收。
// retain
-(void)setName:(NSString *)name {
[name retain];
[_name release];
_name = name;
}
// copy
-(void)setName:(NSString *)name
{
[_name release];
_name = [name copy];
}
1、淺談iOS內(nèi)存管理機(jī)制
iOS內(nèi)存管理機(jī)制的原理是引用計數(shù),引用計數(shù)簡單來說就是統(tǒng)計一塊內(nèi)存的所有權(quán),當(dāng)這塊內(nèi)存被創(chuàng)建出來的時候,它的引用計數(shù)從0增加到1,表示有一個對象或指針持有這塊內(nèi)存,擁有這塊內(nèi)存的所有權(quán),如果這時候有另外一個對象或指針指向這塊內(nèi)存,那么為了表示這個后來的對象或指針對這塊內(nèi)存的所有權(quán),引用計數(shù)加1變?yōu)?,之后若有一個對象或指針不再指向這塊內(nèi)存時,引用計數(shù)減1,表示這個對象或指針不再擁有這塊內(nèi)存的所有權(quán),當(dāng)一塊內(nèi)存的引用計數(shù)變?yōu)?,表示沒有任何對象或指針持有這塊內(nèi)存,系統(tǒng)便會立刻釋放掉這塊內(nèi)存。
其中在開發(fā)時引用計數(shù)又分為ARC(自動內(nèi)存管理)和MRC(手動內(nèi)存管理)。ARC的本質(zhì)其實就是MRC,只不過是系統(tǒng)幫助開發(fā)者管理已創(chuàng)建的對象或內(nèi)存空間,自動在系統(tǒng)認(rèn)為合適的時間和地點(diǎn)釋放掉已經(jīng)失去作用的內(nèi)存空間,原理是一樣的。雖然ARC操作起來很方便,不但減少了代碼量,而且降低了內(nèi)存出錯的概率,但因為ARC不一定會及時釋放,所以程序有時候可能會占用內(nèi)存較大。而MRC若做得好,通過手動管理,及時釋放掉不需要的內(nèi)存空間,便可保證程序長時間運(yùn)行在良好狀態(tài)上。
在MRC中會引起引用計數(shù)變化的關(guān)鍵字有:alloc,retain,copy,release,autorelease。(strong關(guān)鍵字只用于ARC,作用等同于retain)
alloc:
當(dāng)一個類的對象創(chuàng)建,需要開辟內(nèi)存空間的時候,會使用alloc,alloc是一個類方法,只能用類調(diào)用,它的作用是開辟一塊新的內(nèi)存空間,并使這塊內(nèi)存的引用計數(shù)從0增加到1,注意,是新的內(nèi)存空間,每次用類alloc出來的都是一塊新的內(nèi)存空間,與上一次alloc出來的內(nèi)存空間沒有必然聯(lián)系,而且上一次alloc出來的內(nèi)存空間仍然存在,不會被釋放。
retain:
retain是一個實例方法,只能由對象調(diào)用,它的作用是使這個對象的內(nèi)存空間的引用計數(shù)加1,并不會新開辟一塊內(nèi)存空間,通常于賦值是調(diào)用。
如:對象2=[對象1 retain];
表示對象2同樣擁有這塊內(nèi)存的所有權(quán)。若只是簡單地賦值;
如:對象2=對象1;
那么當(dāng)對象1的內(nèi)存空間被釋放的時候,對象2便會成為野指針,再對對象2進(jìn)行操作便會造成內(nèi)存錯誤。
copy:
copy同樣是一個實例方法,只能由對象調(diào)用,返回一個新的對象,它的作用是復(fù)制一個對象到一塊新的內(nèi)存空間上,舊內(nèi)存空間的引用計數(shù)不會變化,新的內(nèi)存空間的引用計數(shù)從0增加到1,也就是說,雖然內(nèi)容一樣,但實質(zhì)上是兩塊內(nèi)存,相當(dāng)于克隆,一個變成兩個。
其中copy又分為淺拷貝、深拷貝和真正的深拷貝:
淺拷貝只是拷貝地址與retain等同;
深拷貝是拷貝內(nèi)容,會新開辟新內(nèi)存,與retain不一樣;
真正的深拷貝是對于容器類來說的,如數(shù)組類、字典類和集合類(包括可變和不可變)。
假設(shè)有一個數(shù)組類對象,普通的深拷貝會開辟一塊新內(nèi)存存放這個對象,但這個數(shù)組對象里面的各個元素的地址卻沒有改變也就是說數(shù)組元素只是進(jìn)行了retain或者淺拷貝而已,并沒有創(chuàng)建新的內(nèi)存空間。
而真正的深拷貝,不但數(shù)組對象本身進(jìn)行了深拷貝,連數(shù)組元素都進(jìn)行了深拷貝,即為各個數(shù)組元素開辟了新的內(nèi)存空間。
release:
release是一個實例方法,同樣只能由對象調(diào)用,它的作用是使對象的內(nèi)存空間的引用計數(shù)減1,若引用計數(shù)變?yōu)?則系統(tǒng)會立刻釋放掉這塊內(nèi)存。如果引用計數(shù)為0的基礎(chǔ)上再調(diào)用release,便會造成過度釋放,使內(nèi)存崩潰;
autorelease:
autorelease是一個實例方法,同樣只能由對象調(diào)用,它的作用于release類似,但不是立刻減1,相當(dāng)于一個延遲的release,通常用于方法返回值的釋放,如便利構(gòu)造器。autorelease會在程序走出自動釋放池時執(zhí)行,通常系統(tǒng)會自動生成自動釋放池(即使是MRC下),也可以自己設(shè)定自動釋放池,如:
@autoreleasepool{
obj= [[NSObject alloc]init];
[obj autorelease];
}
當(dāng)程序走出“}”時obj的引用計數(shù)就會減1.
除了以上所述的關(guān)鍵字,還有一些方法會引起引用計數(shù)的變化,如UI中父視圖添加、移除子視圖,導(dǎo)航控制器或視圖控制器推出新的視圖控制器以及返回,容器類(數(shù)組、字典和集合)添加和移除元素。
當(dāng)子視圖添加到父視圖上時,子視圖的引用計數(shù)加1,移除時引用計數(shù)減1,若父視圖引用計數(shù)變?yōu)?內(nèi)存被釋放,其所有的子視圖都會被release一次,即引用計數(shù)減1,原則上只有這三種情況子視圖的引用計數(shù)會發(fā)生變化,其他如父視圖引用計數(shù)的加減都不會影響到子視圖。
容器類的情況與視圖類似,添加元素,該元素引用計數(shù)加1,移除元素,該元素引用計數(shù)減1,容器引用計數(shù)變?yōu)?所占用內(nèi)存被釋放,容器所有元素release,引用計數(shù)減1,其他情況下容器本身的引用計數(shù)變化不會影響到容器內(nèi)元素的引用計數(shù)變化。
導(dǎo)航控制器或視圖控制器推出新的視圖控制器會使被推出的視圖控制器的引用計數(shù)加1,該視圖控制器返回的時候引用計數(shù)減1,具體方法如下:
導(dǎo)航控制器推出視圖控制器調(diào)用方法:
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
返回時同樣用導(dǎo)航控制器調(diào)用方法:
- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
視圖控制器推出視圖控制器調(diào)用方法:
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion
返回時被推出的視圖控制器調(diào)用方法:
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion
應(yīng)注意:當(dāng)一個對象的引用計數(shù)變?yōu)?占用內(nèi)存被釋放時,會調(diào)用 - (void)dealloc方法,所以如果在MRC下自定義類,必須在該方法里將該類中屬性關(guān)鍵字設(shè)置為retain或copy的屬性release一次,以免造成內(nèi)存泄露,重寫方法不要忘記在第一行添加[super dealloc];。