在iphone開發過程中,代碼中的內存泄露我們很容易用內存檢測工具leaks 檢測出來,並一一改之,但有些是因為ios 的缺陷和用法上的錯誤,leaks 檢測工具並不能檢測出來,你只會看到大量的內存被使用,最后收到didReceiveMemoryWarning,最終導致程序崩潰。以下是開發過程中遇到的一些問題和網上的一些資料,總結了一下:
一、[UIImage imageNamed:]只適合與UI界面中的貼圖的讀取,較大的資源文件應該盡量避免使用
用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]
第一種方法為常見方法,利用它可以方便加載資源圖片。用imageNamed的方式加載時,會把圖像數據根據它的名字緩存在系統內存中,以提高imageNamed方法獲得相同圖片的image對象的性能。即使生成的對象被 autoReleasePool釋放了,這份緩存也不釋放。而且沒有明確的釋放方法。如果圖像比較大,或者圖像比較多,用這種方式會消耗很大的內存。
第二種方法加載的圖片是不會緩存的。得到的對象時autoRelease的,當autoReleasePool釋放時才釋放。
第三種方法要手動release掉。不系統緩存。release后立即釋放,一般用在封面等圖比較大的地方。
二、 滑動列表的時候,使用UITableView的reuse機制
- (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 方法會把隱藏的界面拿來重用,這樣節省很多資源。
三、要大量創建局部變量的時候,可以創建內嵌的autorelease pool來及時釋放內存
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"];//產生的對象是autorelease的。 [loopPool release]; } [pool release]; return (0); } // main
詳細查看:iPhone/Mac Objective-C內存管理教程和原理剖析(一)基本原理
四、頻繁打開和關閉SQLite,導致內存不斷的增長
SQLite的數據庫本質上來講就是一個磁盤上的文件,頻繁打開和關閉是很耗時和浪費資源的,可以設置SQLite的長連接方式;避免頻繁的打開和關閉數據庫;
五、在UITableView 的cellForRowAtIndexPath 代理中不要使用 stringWithFormat 方法
定義一個字符串變量有很多方法,最簡單的就是 NSString *str = @“abc”, 還有initWithString、stringWithFormat和stringWithCString等等。大量的字符操作時,不同的方法消耗不同的內存。
以下測試代碼轉自:http://www.cocoachina.com/bbs/read.php?tid-17652-fpage-9.html
//測試機器 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 內存基本穩定不變 NSString *t=[[NSString alloc] initWithString:@"abccc"]; [t release]; }*/ /* { //avg=0.026101 內存基本穩定不變 NSString *astring = @"abcc"; }*/ /* { //avg=0.278873 內存基本穩定不變 NSString *astring = [[NSString alloc] init]; astring = @"abcc"; [astring release]; }*/ /* { //avg=2.737541 內存基本穩定不變 char *Cstring = "abcc"; NSString *astring = [[NSString alloc] initWithCString:Cstring]; [astring release]; }*/ /* { //avg=3.619728 內存增長過快 NSString *a=[NSString stringWithString:@"abcc"]; }*/ /* { //太長時間,內存增長過快 NSString *a=[NSString stringWithFormat:@"abcc%d",i]; } */ /* { //avg=0.034632 內存基本穩定不變 char a[]="abcc"; }*/ /* { //18.1555 內存稍有增長 NSString *a=[[NSString alloc] initWithFormat:@"abcc%d",i]; [a release]; }*/ /* { //avg=2.276076 內存基本穩定不變 char a[32]; sprintf(a,"abcc%d",i); }*/ /* { //太長時間,內存增長過快 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 即耗時又耗內存,所以在cellForRowAtIndexPath 繪制cell 的時消耗大量內存和時間,造成界面滑動不流暢。
六、關於 colorWithPatternImage 的內存泄露
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bg.png"]];
此方法用圖片來設置view的背景顏色,但是某些設備上會導致內存泄露,詳細查看:
http://blog.csdn.net/cococoolwhj/article/details/6942981
http://www.cocoaintheshell.com/2011/01/colorwithpatternimage-memory-usage/