ios 内存使用陷阱
在iphone開(kāi)發(fā)過(guò)程中,代碼中的內(nèi)存泄露我們很容易用內(nèi)存檢測(cè)工具leaks 檢測(cè)出來(lái),并一一改之,但有些是因?yàn)閕os 的缺陷和用法上的錯(cuò)誤,leaks 檢測(cè)工具并不能檢測(cè)出來(lái),你只會(huì)看到大量的內(nèi)存被使用,最后收到didReceiveMemoryWarning,最終導(dǎo)致程序崩潰。以下是開(kāi)發(fā)過(guò)程中遇到的一些問(wèn)題和網(wǎng)上的一些資料,總結(jié)了一下:
?
一、[UIImage imageNamed:]只適合與UI界面中的貼圖的讀取,較大的資源文件應(yīng)該盡量避免使用
用UIImage加載本地圖像最常用的是下面三種:
1.用imageNamed方法
[UIImage imageNamed:ImageName];2.用 imageWithContentsOfFile 方法
NSString *thumbnailFile = [NSString stringWithFormat:@"%@/%@.png", [[NSBundle mainBundle] resourcePath], fileName]; UIImage *thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile];3. 用initWithContentsFile方法
UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath]?
第一種方法為常見(jiàn)方法,利用它可以方便加載資源圖片。用imageNamed的方式加載時(shí),會(huì)把圖像數(shù)據(jù)根據(jù)它的名字緩存在系統(tǒng)內(nèi)存中,以提高imageNamed方法獲得相同圖片的image對(duì)象的性能。即使生成的對(duì)象被 autoReleasePool釋放了,這份緩存也不釋放。而且沒(méi)有明確的釋放方法。如果圖像比較大,或者圖像比較多,用這種方式會(huì)消耗很大的內(nèi)存。
第二種方法加載的圖片是不會(huì)緩存的。得到的對(duì)象時(shí)autoRelease的,當(dāng)autoReleasePool釋放時(shí)才釋放。
第三種方法要手動(dòng)release掉。不系統(tǒng)緩存。release后立即釋放,一般用在封面等圖比較大的地方。
?
二、?滑動(dòng)列表的時(shí)候,使用UITableView的reuse機(jī)制
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; }?
dequeueReusableCellWithIdentifier 方法會(huì)把隱藏的界面拿來(lái)重用,這樣節(jié)省很多資源。
?
三、要大量創(chuàng)建局部變量的時(shí)候,可以創(chuàng)建內(nèi)嵌的autorelease pool來(lái)及時(shí)釋放內(nèi)存
int main (int argc, const char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int i, j; for (i = 0; i < 100; i++ ) {NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];for (j = 0; j < 100000; j++ )[NSString stringWithFormat:@"1234567890"];//產(chǎn)生的對(duì)象是autorelease的。 [loopPool release]; } [pool release]; return (0); } // main?
詳細(xì)查看:iPhone/Mac Objective-C內(nèi)存管理教程和原理剖析(一)基本原理
四、頻繁打開(kāi)和關(guān)閉SQLite,導(dǎo)致內(nèi)存不斷的增長(zhǎng)
SQLite的數(shù)據(jù)庫(kù)本質(zhì)上來(lái)講就是一個(gè)磁盤上的文件,頻繁打開(kāi)和關(guān)閉是很耗時(shí)和浪費(fèi)資源的,可以設(shè)置SQLite的長(zhǎng)連接方式;避免頻繁的打開(kāi)和關(guān)閉數(shù)據(jù)庫(kù);
?
五、在UITableView 的cellForRowAtIndexPath 代理中不要使用 stringWithFormat 方法
定義一個(gè)字符串變量有很多方法,最簡(jiǎn)單的就是 NSString *str = @“abc”, 還有initWithString、stringWithFormat和stringWithCString等等。大量的字符操作時(shí),不同的方法消耗不同的內(nèi)存。
以下測(cè)試代碼轉(zhuǎn)自:http://www.cocoachina.com/bbs/read.php?tid-17652-fpage-9.html
//測(cè)試機(jī)器 2.4 GHz Intel Core 2Duo????2GB 667 MHz DDR2?? GCC 4.2- (void)testStringSpeed:(id)sender {NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];[textField setStringValue:@""];int testi,testnum=10;float c,tm=0.0;for(testi=0;testi<testnum;testi++){NSDate *beg=[NSDate date];int i,n=10000000;for(i=0;i<n;i++){//avg=0.030204/*{//avg=0.594266 內(nèi)存基本穩(wěn)定不變NSString *t=[[NSString alloc] initWithString:@"abccc"];[t release];}*//*{//avg=0.026101 內(nèi)存基本穩(wěn)定不變NSString *astring = @"abcc";}*//*{//avg=0.278873 內(nèi)存基本穩(wěn)定不變NSString *astring = [[NSString alloc] init];astring = @"abcc";[astring release];}*//*{//avg=2.737541 內(nèi)存基本穩(wěn)定不變char *Cstring = "abcc";NSString *astring = [[NSString alloc] initWithCString:Cstring];[astring release];}*//*{//avg=3.619728 內(nèi)存增長(zhǎng)過(guò)快NSString *a=[NSString stringWithString:@"abcc"];}*//*{//太長(zhǎng)時(shí)間,內(nèi)存增長(zhǎng)過(guò)快NSString *a=[NSString stringWithFormat:@"abcc%d",i];}*//*{//avg=0.034632 內(nèi)存基本穩(wěn)定不變char a[]="abcc";}*//*{//18.1555 內(nèi)存稍有增長(zhǎng)NSString *a=[[NSString alloc] initWithFormat:@"abcc%d",i];[a release];}*//*{//avg=2.276076 內(nèi)存基本穩(wěn)定不變char a[32];sprintf(a,"abcc%d",i);}*//*{//太長(zhǎng)時(shí)間,內(nèi)存增長(zhǎng)過(guò)快NSMutableString *a=[[NSMutableString alloc] init];[a stringByAppendingFormat:@"abcc%d",i];[a release];}*/}c=[[NSDate date] timeIntervalSinceDate:beg];tm+=c;[textField setStringValue:[NSString stringWithFormat:@"%@\n%d=%f",[textField stringValue],testi+1,c]];}[textField setStringValue:[NSString stringWithFormat:@"%@\navg=%f",[textField stringValue],(float)tm/testnum]];[pool release]; }
?
由于stringWithFormat 即耗時(shí)又耗內(nèi)存,所以在cellForRowAtIndexPath 繪制cell 的時(shí)消耗大量?jī)?nèi)存和時(shí)間,造成界面滑動(dòng)不流暢。
?
六、關(guān)于?colorWithPatternImage 的內(nèi)存泄露
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bg.png"]];此方法用圖片來(lái)設(shè)置view的背景顏色,但是某些設(shè)備上會(huì)導(dǎo)致內(nèi)存泄露,詳細(xì)查看:
http://blog.csdn.net/cococoolwhj/article/details/6942981
http://www.cocoaintheshell.com/2011/01/colorwithpatternimage-memory-usage/
?
轉(zhuǎn)載于:https://www.cnblogs.com/zeejun/archive/2012/05/08/2485535.html
總結(jié)
以上是生活随笔為你收集整理的ios 内存使用陷阱的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 正则表达式(一)
- 下一篇: WP7之Application Bar控