溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Objective-C中內(nèi)存管理

發(fā)布時(shí)間:2020-07-01 20:32:04 來(lái)源:網(wǎng)絡(luò) 閱讀:655 作者:HDDevTeam 欄目:移動(dòng)開(kāi)發(fā)

 iOS中內(nèi)存管理

iOS內(nèi)存管理簡(jiǎn)介

    Objective-C的內(nèi)存管理機(jī)制與.Net/Java不同,它沒(méi)有提供全自動(dòng)的垃圾回收機(jī)制,需要我們進(jìn)行手動(dòng)管理,其本質(zhì)相當(dāng)于在C語(yǔ)言的基礎(chǔ)上稍微加了一些自動(dòng)方法。iOS平臺(tái)中的內(nèi)存管理采用了引用計(jì)數(shù)的管理機(jī)制,當(dāng)創(chuàng)建一個(gè)對(duì)象使用alloc或者allocWithZone方法時(shí),引用計(jì)數(shù)就會(huì)+1;當(dāng)釋放對(duì)象使用release方法時(shí),引用計(jì)數(shù)就會(huì)-1,這意味著每一個(gè)對(duì)象都會(huì)跟蹤有多少對(duì)象引用它,一旦引用計(jì)數(shù)為0,該對(duì)象的內(nèi)存就會(huì)被釋放掉。另外,iOS還提供了一種延時(shí)釋放機(jī)制AutoRelease,以這種方式申請(qǐng)的內(nèi)存,開(kāi)發(fā)者無(wú)需手動(dòng)釋放,系統(tǒng)會(huì)在某一時(shí)機(jī)釋放該內(nèi)存。因此,開(kāi)發(fā)人員在開(kāi)發(fā)應(yīng)用的時(shí)候必須合理的控制何時(shí)創(chuàng)建對(duì)象、保存對(duì)象以及從內(nèi)存中釋放對(duì)象。如果使用太多的內(nèi)存,iPhone會(huì)警告應(yīng)用程序委托和UIViewController,委托收到applicationDidReceiveMemoryWarning:回調(diào),視圖控制器會(huì)收到didReceiveMemoryWarning,如果繼續(xù)使用太多內(nèi)存的話,iPhone將終止你的應(yīng)用程序,使你的用戶回到SpringBoard。很明顯,這不是我們所希望得到的用戶體驗(yàn)。

iOS內(nèi)存使用原則:

1.  對(duì)象的所有權(quán)與銷毀

誰(shuí)創(chuàng)建,誰(shuí)釋放:如果是以alloc,new或者copy創(chuàng)建的對(duì)象,則必須調(diào)用release或者autorelease方法釋放內(nèi)存,如果沒(méi)有釋放,則導(dǎo)致內(nèi)存泄漏。除了allocnew,或copy之外的方法創(chuàng)建的對(duì)象都被聲明了autorelease。

誰(shuí)retain,誰(shuí)釋放:如果對(duì)一個(gè)對(duì)象發(fā)送retain消息,其引用計(jì)數(shù)會(huì)+1,則使用完必須發(fā)送releaseautorelease方法釋放內(nèi)存或恢復(fù)引用計(jì)數(shù),如果沒(méi)有釋放,同樣導(dǎo)致內(nèi)存泄漏。

沒(méi)創(chuàng)建且沒(méi)retain,別釋放:不要釋放那些不是自己alloc或者retain的對(duì)象,否則程序會(huì)crash,不要釋放autorelease的對(duì)象,否則程序會(huì)crash

2.   對(duì)象的深拷貝與淺拷貝

深拷貝:復(fù)制指針?biāo)玫臄?shù)據(jù),并將其賦給副本的實(shí)例變量。其流程是先創(chuàng)建一個(gè)

新的對(duì)象且引用計(jì)數(shù)為1,并用就舊對(duì)象的值初始化這個(gè)新對(duì)象。

ClassA *objA=[[ClassA alloc] init];

ClassA *objB=[objA copy];

objB是一個(gè)新對(duì)象,引用計(jì)數(shù)為1,objB的數(shù)據(jù)等同于objA的數(shù)據(jù)。

注:objB需要釋放,否則會(huì)內(nèi)存泄漏

淺拷貝:將原始對(duì)象的指針復(fù)制到副本中,原始對(duì)象和副本共享引用數(shù)據(jù)。其流程是,無(wú)需引入新的對(duì)象,把原有對(duì)象的引用計(jì)數(shù)+1即可。

ClassA *objA=[[ClassA alloc] init];

ClassA *objB=[objA retain];

注:objB需要釋放,恢復(fù)objA的引用計(jì)數(shù),否則會(huì)引起內(nèi)存泄漏。

3.  對(duì)象的存取方法

屬性的聲明與實(shí)現(xiàn)

變量聲明的常用屬性類型包括:

readonly屬性:只能讀,不能寫;

assign屬性:是默認(rèn)屬性,直接賦值,沒(méi)有任何保留與釋放問(wèn)題;

retain屬性:會(huì)增加原有對(duì)象的引用計(jì)數(shù),并且在賦值前會(huì)釋放原有對(duì)象,然后再進(jìn)行賦值。

copy屬性:會(huì)復(fù)制原有對(duì)象,并在賦值前釋放原有對(duì)象,然后再進(jìn)行賦值。

屬性聲明可能帶來(lái)的問(wèn)題:

當(dāng)一個(gè)非指針變量使用retain(或者copy)這個(gè)屬性時(shí),盡量不要顯性的release這個(gè)變量,直接給這個(gè)變量置空即可,否則容易產(chǎn)生過(guò)度釋放,導(dǎo)致程序crash。

iOSautorelease機(jī)制

1.一般地,在新建一個(gè)iPhone項(xiàng)目的時(shí)候,xcode會(huì)自動(dòng)在mian函數(shù)中為你創(chuàng)建一個(gè)autorelease pool,其全名是NSAutoreleasePool,是Objective-C中的一個(gè)類。

2.在NSAutoreleasePool中包含了一個(gè)可變數(shù)組,用來(lái)存儲(chǔ)被聲明為autorelease的所有對(duì)象,如果一個(gè)對(duì)象被聲明為autorelease,系統(tǒng)所做的工作就是把這個(gè)對(duì)象加入到這個(gè)數(shù)組中去。

3.當(dāng)AutoreleasePool自身被銷毀的時(shí)候,它會(huì)遍歷這個(gè)數(shù)組,release數(shù)組中的每一個(gè)成員,如果此時(shí)數(shù)組中成員的retain count1,那么release之后,retain count0,對(duì)象正式被銷毀。如果此時(shí)數(shù)組中成員的retain count大于1,那么release之后,retain count大于0,此對(duì)象依然沒(méi)有被銷毀,內(nèi)存泄漏。

Main函數(shù)如下:

int main(int argc,char *argv[])

{

         NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];

         int retVal=UIApplicationMain(argc,argv,nil,nil);

         [pool release];

         return retVal;

}

4.自動(dòng)釋放池所涉及到的一些常見(jiàn)問(wèn)題

ios程序開(kāi)發(fā)的時(shí)候,會(huì)經(jīng)常遇到在滑動(dòng)列表,頻繁訪問(wèn)圖片,頻繁打開(kāi)或關(guān)閉數(shù)據(jù)庫(kù)的時(shí)候,內(nèi)存會(huì)莫名其妙的增長(zhǎng),其實(shí),這些都很有可能是autorelease機(jī)制的所導(dǎo)致的。

分析如下:

滑動(dòng)列表的時(shí)候,內(nèi)存增長(zhǎng)原因:沒(méi)有使用UITableVIewreuse機(jī)制,導(dǎo)致每顯示一個(gè)cell都用autorelease的方式重新alloc一次,導(dǎo)致cell的內(nèi)存不斷增加?;蛘?,每個(gè)cell會(huì)顯示一個(gè)單獨(dú)的UIView,在UIView發(fā)生內(nèi)存泄漏,導(dǎo)致cell內(nèi)存不斷增長(zhǎng)。

頻繁訪問(wèn)圖片的時(shí)候,內(nèi)存增長(zhǎng)原因:頻繁的訪問(wèn)網(wǎng)絡(luò)圖片,導(dǎo)致ios內(nèi)部API,會(huì)不斷的分配autorelease方式的buffer來(lái)處理圖片的解碼與顯示。

頻繁打開(kāi)和關(guān)閉SQLite數(shù)據(jù)庫(kù),內(nèi)存增長(zhǎng)原因:在進(jìn)行sqlite頻繁打開(kāi)和關(guān)閉操作,而且讀取的數(shù)據(jù)buffer較大,那么sqlite在每次打開(kāi)關(guān)閉的時(shí)候,都會(huì)利用autorelease的方式分配51k的內(nèi)存,如果訪問(wèn)次數(shù)多,內(nèi)存馬上會(huì)頂?shù)綆资祝踔辽习僬?,所以,?duì)于頻繁讀寫數(shù)據(jù)庫(kù)且數(shù)據(jù)buffer較大的情況,可以設(shè)置sqlite長(zhǎng)連接方式,避免頻繁打開(kāi)或關(guān)閉數(shù)據(jù)庫(kù)。

iOS內(nèi)存使用誤區(qū)

1重復(fù)釋放:不要釋放不是自己創(chuàng)建的對(duì)象,釋放自己或系統(tǒng)的autorelease對(duì)象,app都會(huì)crash。

2循環(huán)引用:循環(huán)引用,容易產(chǎn)生野引用,內(nèi)存無(wú)法回收,最終導(dǎo)致內(nèi)存泄漏??梢酝ㄟ^(guò)弱引用的方式打破循環(huán)引用鏈。所謂的弱引用就是不需要retain,直接采取賦值的方式,這樣的話可以避免循環(huán)引用,同時(shí)也要注意避免重復(fù)釋放的問(wèn)題。

IOS內(nèi)存警報(bào)處理流程

1. app收到系統(tǒng)發(fā)過(guò)來(lái)的memory warningnotice;

2. app釋放占用較大的內(nèi)存;

3. 系統(tǒng)回收此app所創(chuàng)建的autorelease的對(duì)象;

4. app返回到已經(jīng)打開(kāi)的頁(yè)面時(shí),系統(tǒng)重新調(diào)用viewdidload方法,view重新加載頁(yè)面數(shù)據(jù),重新進(jìn)行顯示;

iOS內(nèi)存檢查工具

1.   編譯分析工具Analyze

可以發(fā)現(xiàn)編譯中的warning,內(nèi)存泄漏隱患,甚至是邏輯上的問(wèn)題,從而避免嚴(yán)重的由于內(nèi)存引起的嚴(yán)重的bug。

內(nèi)存泄漏隱患提示:Potential Leak of an object allocated on line…

數(shù)據(jù)賦值隱患提示:The left operand of…is a garbage value;

對(duì)象引用隱患提示:Reference-Counted object is used after it is release;

2.   內(nèi)存檢測(cè)工具

內(nèi)存泄漏檢測(cè)工具——Leak

內(nèi)存猛增檢測(cè)工具——Allocations

二者的詳細(xì)使用,可以自己查閱相關(guān)信息進(jìn)行了解。

總之,對(duì)于IOS中內(nèi)存的管理,需要我們?cè)趯?shí)際的程序開(kāi)發(fā)中通過(guò)編寫相應(yīng)代碼,以及調(diào)試相關(guān)由內(nèi)存引起的的問(wèn)題,才可以得到比較好的體會(huì)。如果在開(kāi)發(fā)過(guò)程中,不能按照分配原則進(jìn)行內(nèi)存的合理分配與釋放,將會(huì)對(duì)整個(gè)應(yīng)用程序的性能造成很嚴(yán)重的影響,甚至導(dǎo)致其崩潰。所以開(kāi)發(fā)者必須在深刻理解ios內(nèi)存管理機(jī)制的基礎(chǔ)上,采用最佳的內(nèi)存管理方式,才能獲得優(yōu)良的用戶體驗(yàn)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI