日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

iOS内存暴增问题追查与使用陷阱

發(fā)布時(shí)間:2024/10/12 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS内存暴增问题追查与使用陷阱 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

iOS平臺(tái)的內(nèi)存使用引用計(jì)數(shù)的機(jī)制,并且引入了半自動(dòng)釋放機(jī)制;這種使用上的多樣性,導(dǎo)致開發(fā)者在內(nèi)存使用上非常容易出現(xiàn)內(nèi)存泄漏和內(nèi)存莫名的增長(zhǎng)情況; 本文會(huì)介紹iOS平臺(tái)的內(nèi)存使用原則與使用陷阱; 深度剖析autorelease機(jī)制;低內(nèi)存報(bào)警后的處理流程;并結(jié)合自身實(shí)例介紹內(nèi)存暴增的問題追查記錄以及相關(guān)工具的使用情況;

TAG

內(nèi)存暴增,內(nèi)存泄漏,autorelease;內(nèi)存報(bào)警;

1 iOS平臺(tái)內(nèi)存管理介紹

iOS平臺(tái)的內(nèi)存管理采用引用計(jì)數(shù)的機(jī)制;當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí)使用alloc或者allWithZone方法時(shí),引用計(jì)數(shù)就會(huì)+1?;當(dāng)釋放對(duì)象使用release方法時(shí),引用計(jì)數(shù)就是-1?;這就意味著每一個(gè)對(duì)象都會(huì)跟蹤有多少其他對(duì)象引用它,一旦引用計(jì)數(shù)為0,該對(duì)象的內(nèi)存就會(huì)被釋放掉;另外,iOS也提供了一種延時(shí)釋放的機(jī)制AutoRelease,以這種方式申請(qǐng)的內(nèi)存,開發(fā)者無需手動(dòng)釋放,系統(tǒng)會(huì)在某一時(shí)機(jī)釋放該內(nèi)存; 由于iOS平臺(tái)的這種內(nèi)存管理的多樣性,導(dǎo)致開發(fā)者在內(nèi)存使用上很容易出現(xiàn)內(nèi)存泄漏或者程序莫名崩潰的情況,本文會(huì)詳細(xì)介紹iOS平臺(tái)內(nèi)存的使用規(guī)范與技巧以及如何利用工具避免或者發(fā)現(xiàn)問題;?

2 iOS平臺(tái)內(nèi)存使用原則

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

2.1.1 誰(shuí)創(chuàng)建,誰(shuí)釋放;

如果是以alloc,new或者copy,mutableCopy創(chuàng)建的對(duì)象,則必須調(diào)用release或者autorelease方法釋放內(nèi)存;

例如: ClassA* obj = [[ClassAalloc?] init];

……

[objrelease?];

obj = nil;? /* 防止野指針*/

2.1.2 誰(shuí)retain,誰(shuí)釋放;

如果對(duì)一個(gè)對(duì)象發(fā)送 retain消息,其引用計(jì)數(shù)會(huì)+1,則使用完必須發(fā)送release或者autorelease方法釋放內(nèi)存或恢復(fù)引用計(jì)數(shù);

例如:ClassA* obj = [[ClassAalloc?] init];/* 引用計(jì)數(shù) 1*/

ClassA* obj1 = obj;

[obj1retain?]; ?/*引用計(jì)數(shù) 2*/

……

[obj1release?]; /* 引用計(jì)數(shù) 1*/

obj1=nil;

[objrelease?]; /* 引用計(jì)數(shù) 0*/

obj=nil;

2.1.3 使用完,要釋放;

不論使用的是alloc(copy,new)創(chuàng)建的對(duì)象,還是通過retain增加了引用計(jì)數(shù),在對(duì)象使用完后,都要調(diào)用release或者autorelease方法;釋放內(nèi)存,確保沒有內(nèi)存泄漏;

2.1.4 沒創(chuàng)建且沒retain,別釋放;

不要釋放那些不是自己alloc或者retain的對(duì)象,否則程序會(huì)crash?;

不要釋放autorelease的對(duì)象,否則程序會(huì)crash

例如:

ClassA* obj = [[[ClassAalloc?] init]autorelease?];/* 自動(dòng)釋放*/

……

[objrelease?]; /* 程序crash */

obj=nil;

NSString* content = [NSString stringWithFormat: @”…”];

/* 系統(tǒng)返回的對(duì)象是autorelease?的 */

……

[contentrelease?]; /* 試圖釋放一個(gè)autorelease對(duì)象,程序會(huì)crash?*/

content=nil;

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

一般來說,復(fù)制一個(gè)對(duì)象包括創(chuàng)建一個(gè)新的實(shí)例,并以原始對(duì)象中的值初始化這個(gè)新的實(shí)例。復(fù)制非指針型實(shí)例變量的值很簡(jiǎn)單,比如布爾,整數(shù)和浮點(diǎn)數(shù)。復(fù)制指 針型實(shí)例變量有兩種方法。一種方法稱為淺拷貝,即將原始對(duì)象的指針值復(fù)制到副本中。因此,原始對(duì)象和副本共享引用數(shù)據(jù)。另一種方法稱為深拷貝,即復(fù)制指針 所引用的數(shù)據(jù),并將其賦給副本的實(shí)例變量。

2.2.1 深拷貝

實(shí)例變量的set方法的實(shí)現(xiàn)應(yīng)該能夠反映出您需要使用的復(fù)制類型。如果相應(yīng)的set方法復(fù)制了新的值,如下面的方法所示,那么您應(yīng)該深拷貝這個(gè)實(shí)例變量:

- (void)setMyVariable:(id)newValue
{
[myVariable autorelease];
myVariable = [newValuecopy?];
}

2.2.2 淺拷貝

如果相應(yīng)的set方法保留了新的值,如下面的方法所示,那么您應(yīng)該淺拷貝這個(gè)實(shí)例變量:

- (void)setMyVariable:(id)newValue
{
[myVariable autorelease];
myVariable = [newValueretain?];
}

2.3 對(duì)象的存取方法

2.3.1 屬性聲明和實(shí)現(xiàn)

一般在程序的頭文件中,會(huì)設(shè)置成員變量的屬性,obj-C可以自動(dòng)生成對(duì)成員變量的set?和get?函數(shù);

聲明:

@property (copy) NSString *str; /* 復(fù)制對(duì)象,引用計(jì)數(shù)初始為1*/ @property (readonly) NSString *str1; /* 只讀對(duì)象,不可更改*/ @property (retain) NSString *str2; /* retain對(duì)象,引用計(jì)數(shù)+1*/ @property (assign) int num; /* 非指針變量,直接賦值 */

實(shí)現(xiàn):

@synthesize str; @synthesize str1; @synthesize str2; @synthesize num;

2.3.2 存取方法的內(nèi)部實(shí)現(xiàn)

屬性的聲明和實(shí)現(xiàn),實(shí)際上是系統(tǒng)幫助開發(fā)者自動(dòng)生成了對(duì)成員變量的set和get方法;當(dāng)然開發(fā)者也可以顯性的定義set和get函數(shù);下面介紹一下系統(tǒng)自動(dòng)生成set和get方法的定義,以@property (retain?) NSString *str2; 舉例說明:

@interface ClassA : NSObject

-(NSString *) getStr2;

-(void) setStr2:(NSString *) value;

@end

@implementation ClassA

-(NSString *) getStr2{

return str2;

}

- setStr2:(NSString *) value {

if (str2 != value){? /* 如果參數(shù)與原來的值不同,則先釋放原來的值,然后在賦值并retain */

[str2release?];

str2 = [valueretain?];

}

}

注意: 在屬性中聲明為retain或者copy的成員變量,在delloc函數(shù)中,都要顯性的release;

-(void) dealloc{

[str2release?];

……

}

3 iOS平臺(tái)AutoRelease機(jī)制

3.1 自動(dòng)釋放池的概念

自動(dòng)釋放池是一個(gè)NSAutoreleasePool實(shí)例,其中“包含”已經(jīng)收到autorelease消息的其他對(duì)象;當(dāng)自動(dòng)釋放池被回收時(shí),它會(huì)向其中的每個(gè)對(duì)象發(fā)送一條release消息。一個(gè)對(duì)象可以被數(shù)次放入一個(gè)自動(dòng)釋放池中,并且在每次被放入池中的時(shí)候都會(huì)收到一條release消息。因此,向?qū)ο蟀l(fā)送autorelease消息(而不是release消息)可以至少將該對(duì)象的生命周期延長(zhǎng)至自動(dòng)釋放池本身被釋放的時(shí)候(如果在此期間對(duì)象被保留,則它可以存活更久)。

Cocoa總是期望有一個(gè)自動(dòng)釋放池可用。如果自動(dòng)釋放池不可用,那么自動(dòng)釋放對(duì)象就無法得到釋放,您也就泄漏了內(nèi)存。如果當(dāng)自動(dòng)釋放池不可用的時(shí)候,您發(fā)送了autorelease消息,那么Cocoa會(huì)記錄相應(yīng)的錯(cuò)誤信息。

您可以使用常見的alloc和init消息來創(chuàng)建一個(gè)NSAutoreleasePool對(duì)象,并使用drain?銷毀它。自動(dòng)釋放池應(yīng)該總是在與它被創(chuàng)建時(shí)所處的相同上下文環(huán)境(方法或函數(shù)的調(diào)用,或循環(huán)體)中被銷毀。

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

……

??????? [pool drain];

自動(dòng)釋放池被置于一個(gè)堆棧中,雖然它們通常被稱為被“嵌套”的。當(dāng)您創(chuàng)建一個(gè)新的自動(dòng)釋放池時(shí),它被添加到堆棧的頂部。當(dāng)自動(dòng)釋放池被回收時(shí),它們從堆棧中被刪除。當(dāng)一個(gè)對(duì)象收到送autorelease消息時(shí),它被添加到當(dāng)前線程的目前處于棧頂?shù)淖詣?dòng)釋放池中。

3.2 自動(dòng)釋放池的作用域與嵌套

我們通常會(huì)提及自動(dòng)釋放池是被嵌套的。但是,您也可以認(rèn)為嵌套自動(dòng)釋放池位于一個(gè)堆棧中,其中,“最內(nèi)層”的自動(dòng)釋放池位于棧頂。如前所述,嵌套自動(dòng)釋放池實(shí)際上是這樣實(shí)現(xiàn)的:程序中的每個(gè)線程都維護(hù)一個(gè)自動(dòng)釋放池的堆棧。當(dāng)您創(chuàng)建一個(gè)自動(dòng)釋放池時(shí),它被壓入當(dāng)前線程的堆棧的棧頂。?當(dāng)一個(gè)對(duì)象被自動(dòng)釋放時(shí)—也就是說,當(dāng)一個(gè)對(duì)象收到一條autorelease消息或者當(dāng)它作為一個(gè)參數(shù)被傳入addObject:類方法時(shí)—它總是被放入堆棧頂部的自動(dòng)釋放池中。

因此,自動(dòng)釋放池的作用域是由它在堆棧中的位置以及它的存在情況定義的?。自動(dòng)釋放對(duì)象被添加至棧頂?shù)淖詣?dòng)釋放池中。如果另一個(gè)自動(dòng)釋放 池被創(chuàng)建,則當(dāng)前位于棧頂?shù)某鼐统銎渥饔糜?#xff0c;直到新的池被釋放為止(此時(shí)原來的自動(dòng)釋放池再次成為棧頂?shù)淖詣?dòng)釋放池)。當(dāng)自動(dòng)釋放池本身被釋放的時(shí)候, 它(顯然)就永久地超出其作用域。

如果您釋放了一個(gè)不是位于堆棧頂部的自動(dòng)釋放池,則這會(huì)導(dǎo)致堆棧中所有位于它上面的(未釋放的)自動(dòng)釋放池,連同它們包含的所有對(duì)象一起被釋放。?當(dāng)您用完自動(dòng)釋放池時(shí),如果您一時(shí)疏忽,忘記向它發(fā)送release消息(不推薦您這樣做),那么,當(dāng)嵌套在它外層的自動(dòng)釋放池中的某個(gè)被釋放時(shí),它也會(huì)被釋放。

這種行為對(duì)于異常的處理很有意義。如果發(fā)生異常,并且線程突然轉(zhuǎn)移出當(dāng)前的上下文環(huán)境,則與該上下文相關(guān)聯(lián)的自動(dòng)釋放池將被釋放。但 是,如果被釋放的池不是線程堆棧頂部的池,則所有位于該自動(dòng)釋放池之上的自動(dòng)釋放池也會(huì)被釋放(并在這個(gè)過程中釋放其中所有的對(duì)象)。然后,先前位于被釋 放的池下面的自動(dòng)釋放池則成為線程堆棧最頂端的自動(dòng)釋放池。由于這種行為,異常處理程序則不需要釋放收到autorelease消息的對(duì)象。對(duì)于異常處理程序來說,沒有必要也不值得向它的自動(dòng)釋放池發(fā)送release,除非異常處理程序重新引發(fā)該異常。

3.3 自動(dòng)施放池的手動(dòng)創(chuàng)建與自動(dòng)創(chuàng)建

3.3.1 需要手動(dòng)創(chuàng)建自動(dòng)釋放池

  • 如果你正在編寫一個(gè)不是基于Application Kit的程序,比如命令行工具,則沒有對(duì)自動(dòng)釋放池的內(nèi)置支持;你必須自己創(chuàng)建它們。
  • 如果你生成了一個(gè)從屬線程,則一旦該線程開始執(zhí)行,你必須立即創(chuàng)建你自己的自動(dòng)釋放池;否則,你將會(huì)泄漏對(duì)象。
  • 如果你編寫了一個(gè)循環(huán),其中創(chuàng)建了許多臨時(shí)對(duì)象,你可以在循環(huán)內(nèi)部創(chuàng)建一個(gè)自動(dòng)釋放池,以便在下次迭代之前銷毀這些對(duì)象。這可以幫助減少應(yīng)用程序的最大內(nèi)存占用量。

3.3.2 系統(tǒng)自動(dòng)創(chuàng)建自動(dòng)釋放池

Application Kit會(huì)在一個(gè)事件周期(或事件循環(huán)迭代)的開端—比如鼠標(biāo)按下事件—自動(dòng)創(chuàng)建一個(gè)自動(dòng)釋放池,并且在事件周期的結(jié)尾釋放它.

4 iOS平臺(tái)內(nèi)存使用陷阱

4.1 重復(fù)釋放

在前文已經(jīng)提到,不要釋放不是自己創(chuàng)建的對(duì)象;

釋放自己的autorelease對(duì)象,app會(huì)crash;

釋放系統(tǒng)的autorelease對(duì)象,app會(huì)crash;

4.2 循環(huán)引用

?
循環(huán)引用,容易產(chǎn)生野引用,內(nèi)存無法回收,最終導(dǎo)致內(nèi)存泄漏!可以通過弱引用的方式來打破循環(huán)引用鏈;

5 iOS平臺(tái)內(nèi)存報(bào)警機(jī)制

由于iOS平臺(tái)的內(nèi)存管理機(jī)制,不支持虛擬內(nèi)存,所以在內(nèi)存不足的情況,不會(huì)去Ram上創(chuàng)建虛擬內(nèi)存;所以一旦出現(xiàn)內(nèi)存不足的情況,iOS平臺(tái)會(huì)通知所有已經(jīng)運(yùn)行的app,不論是前臺(tái)app還是后臺(tái)掛起的app,都會(huì)收到 memory warning的notice;一旦app收到memory warning的notice,就應(yīng)該回收占用內(nèi)存較大的變量;

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

1: app收到系統(tǒng)發(fā)過來的memory warning的notice;

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

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

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

5.2 內(nèi)存報(bào)警測(cè)試方法

在Simulate上可以模擬低內(nèi)存報(bào)警消息;

iOS模擬器 -> 硬件 -> 模擬內(nèi)存警告;

開發(fā)者可以在模擬器上來模擬手機(jī)上的低內(nèi)存報(bào)警情況,可以避免由于低內(nèi)存報(bào)警引出的app的莫名crash問題;

6 iOS平臺(tái)內(nèi)存檢查工具

6.1 編譯和分析工具Analyze

iOS的分析工具可以發(fā)現(xiàn)編譯中的warning,內(nèi)存泄漏隱患,甚至還可以檢查出logic上的問題;所以在自測(cè)階段一定要解決Analyze發(fā)現(xiàn)的問題,可以避免出現(xiàn)嚴(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 released;

以上提示均比較嚴(yán)重,可能會(huì)引起嚴(yán)重問題,需要開發(fā)者密切關(guān)注!

6.2 內(nèi)存檢測(cè)工具Leak

內(nèi)存檢測(cè)工具可以通過iOS自帶Leak工具檢測(cè) 是否有內(nèi)存泄漏;

一般通過Leak工具可以很快的檢查出程序哪里有內(nèi)存泄漏,一般這種問題也比較容易解決,可是有時(shí)候即使解決了所有的內(nèi)存泄漏,但還是發(fā)現(xiàn)程序在運(yùn)行中,內(nèi)存還是在不斷的瘋漲,這時(shí)候可能就要借助另外一個(gè)工具Allocations來檢查是那些地方使用的內(nèi)存比較多而且是持續(xù)增長(zhǎng);下面詳細(xì)介紹一下這兩個(gè)工具的使用方法: Leak和Allocations;

Leak工具:?
?
通過Leak工具可以很快發(fā)現(xiàn)代碼中的內(nèi)存泄漏,通過工具也可以很快找到發(fā)生內(nèi)存泄漏的代碼段:?
?
Allocations工具:?
?
此工具會(huì)顯示出所有申請(qǐng)內(nèi)存的地方,并統(tǒng)計(jì)申請(qǐng)的次數(shù)和大小; 從這個(gè)列表中可以找出內(nèi)存申請(qǐng)次數(shù)最多且申請(qǐng)內(nèi)存最大的語(yǔ)句;從而分析出哪些地方使用的內(nèi)存最多,進(jìn)而可以優(yōu)化和改進(jìn);?

上圖是按照申請(qǐng)內(nèi)存多少來排序的,可以方便的了解哪些代碼申請(qǐng)的內(nèi)存多;

注意:?
1:iOS的SQLite 最好不要頻繁的打開和關(guān)閉數(shù)據(jù)庫(kù),這樣SQLite在內(nèi)部會(huì)增加內(nèi)存Cache, 每次會(huì)增長(zhǎng)51K的內(nèi)存buffer,如果頻繁打開和關(guān)閉SQLite的話,內(nèi)存很快就會(huì)漲到幾十兆,甚至上百兆!

2:Image的顯示,從網(wǎng)絡(luò)上下載的圖片或者頭像,Image內(nèi)部API,每次會(huì)增加9K的cache;

7 參考資料

http://www.cocoachina.com/bbs/read.php?tid=15963

http://developer.apple.com/library/IOs/navigation/

by lixin

原文鏈接:?http://www.udpwork.com/redirect/6406


轉(zhuǎn)載于:https://www.cnblogs.com/zsw-1993/archive/2012/10/12/4880812.html

與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的iOS内存暴增问题追查与使用陷阱的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 第四色影音先锋 | 日日夜夜爽 | free性欧美hd另类 | 久久综合鬼色 | 亚洲视频欧美视频 | 久久青青草原亚洲av无码麻豆 | 污视频网站免费在线观看 | 久久久久女| 91打屁股| www.xxx日韩| 久久av一区二区三区亚洲 | 免费草逼网站 | 天天艹日日干 | av黄| 国产51视频 | 苍井空张开腿实干12次 | 国产一区二区三区视频播放 | 国产黑丝一区二区 | 爱爱视频免费看 | 男人日女人逼 | 国产一卡二卡三卡 | 午夜精产品一区二区在线观看的 | 日韩一道本 | 中文字幕免费看 | 日韩女优在线观看 | 日韩成人不卡 | 国产精品美女久久久网av | 视频在线不卡 | 啪啪自拍视频 | 欧美韩日国产 | 欧美69久成人做爰视频 | 国产乱码精品1区2区3区 | 少妇大叫太粗太大爽一区二区 | 久久久精品亚洲 | 男人天堂视频在线观看 | 人妻大战黑人白浆狂泄 | 日本热久久 | 亚洲爱v| 日日日网站| www.一区二区三区 | 女优一区二区三区 | 国产一区视频免费观看 | 99热| 国产日韩欧美在线观看 | 亚洲综合图片一区 | 国产日产精品一区二区 | 亚洲aa | 99爱视频在线观看 | 香蕉视频911 | 性高湖久久久久久久久免费 | 亚洲激情欧美色图 | 激情网综合 | 一二三区在线观看 | 小箩莉末发育娇小性色xxxx | 日韩天堂在线观看 | 国产精美视频 | 最新的av网站 | 337p亚洲精品色噜噜狠狠 | 精品视频入口 | 在线观看成人 | 亚洲在线精品视频 | 91久久视频| 色www亚洲国产阿娇yao | 日韩无砖| 日本少妇xxxxxx | 亚洲论理| 麻豆一区二区三区四区 | 久久久久麻豆v国产精华液好用吗 | 欧美a一级片 | a少妇| cao我| 欧美视频网站 | 欧美黄色a级 | av一卡二卡 | 日韩一卡二卡三卡 | 亚洲一区二区三区在线视频观看 | 性欧美在线视频观看 | 精品伦精品一区二区三区视频密桃 | 亚洲精品无码久久久久 | 青青草成人影视 | 毛片av在线播放 | 国产午夜手机精彩视频 | 欧美日韩精品在线观看视频 | 91精品视频网 | 久久久激情视频 | 青青青青青草 | 亚洲精品黄| 91麻豆网站 | 亚洲综合国产精品 | 欧美字幕 | 先锋影音av在线资源 | 国产精品免费视频一区二区三区 | 欧美精品在欧美一区二区少妇 | av中文字幕免费观看 | 亚洲第一免费播放区 | 久久久久久久久久影视 | 手机在线免费视频 | 免费福利av | 激情婷婷六月 |