zoukankan      html  css  js  c++  java
  • ios 内存使用陷阱 和imageNamed 、imageWithContentsOfFile:(转)

     

     

    在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:@"%@
    %d=%f",[textField stringValue],testi+1,c]];
        }
        [textField setStringValue:[NSString stringWithFormat:@"%@
    avg=%f",[textField stringValue],(float)tm/testnum]];
        [pool release];
    }
    复制代码

     

    由于stringWithFormat 即耗时又耗内存,所以在cellForRowAtIndexPath 绘制cell 的时消耗大量内存和时间,造成界面滑动不流畅。

    六、关于 colorWithPatternImage 的内存泄露

    self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bg.png"]];
  • 相关阅读:
    《我所理解的生活》—读书总结
    《给你一个团队,你能怎么管?》—读书总结
    关于投资那点儿事
    《30岁前的每一天》—读书总结
    《书都不会读,你还想成功》-读书总结
    解决问题—麦肯锡方法:解决问题的七个步骤
    解决问题—基本流程
    关于接入新浪微博第三方登录
    搭建Spring、Spring MVC、Mybatis和Freemarker
    Eclipse+Maven创建webapp项目<二>
  • 原文地址:https://www.cnblogs.com/leevaboo/p/3783263.html
Copyright © 2011-2022 走看看