iOS学习之路:ARC内存清理&缓存清理&效率优化

最近项目中遇到了很多关于内存泄露和缓存清理的问题,尤其是ARC这块内存什么时候释放,以及UIWebview的缓存清理,消耗了很多时间,特别做个总结:

1. 关于ARC内存释放猜想

我们都知道在ARC机制下,我们不需要手动管理内存,例如Autorelease和release等函数都不能调用,系统会自动为我们释放,我们需要做的,仅仅是把指针设置成nil就可以了,如果需要,再把相应的view remove掉就可以了。但是在实际代码过程中,会发现申请的指针在这个函数体执行完毕之后并没有把内存释放掉。在网上搜索了好久也没有什么好的解释。先说下具体的例子吧。

例如有个函数a,作用是生成一张图片,那在函数体里面我们需要new一个指针出来,指向生成的图片,UIImageView* img = [UIImage alloc]init ... 具体就不写了,在函数即将结束的时候,我们将img = nil。到此实际就完成了ARC所要求的用户操作了。但是我们debug时会发现,这快内存并没有实时释放掉。每当我们调用一下函数a,内存就会增大一部分。似乎是系统将我们生成的指针丢在了某块内存池中,但是这个池子什么时候释放掉,是系统说了算的,所以当函数执行完的时候,内存并没有被释放。

那如果解决呢?

我们申请一个全局指针,在整个程序的生命周期都存在,这样每当我们调用函数a的时候,就把这个全局指针指向生成的图片。这样就不会造成每次都要new一块内存出来而释放不掉的问题了。

2. UIWebView缓存清理

项目中要显示很多webview,但是当我们切换web的内容是,发现以前的缓存并没有释放掉,于是就会出现每加载一遍,内存就蹦很多的情况。在网上搜了下解决办法。

最简单的一种是每次在申请之前让webview load一个空的URL:

webView loadHTMLString:NULL baseURL:NULL;

但是这种方法似乎不能完全清理缓存,于是在stackoverflow上搜到了正确的解决办法:http://stackoverflow.com/questions/2523435/how-to-clear-uiwebview-cache

if (lastReq){
    [[NSURLCache sharedURLCache] removeCachedResponseForRequest:lastReq];
    [[NSURLCache sharedURLCache] removeAllCachedResponses];

}

lastReq=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:localUrl]
                                   cachePolicy:NSURLRequestReloadIgnoringCacheData
                               timeoutInterval:10000];
[lastReq setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];

[self.mainWebView loadRequest:lastReq];

其实给URLRequest设置一个cachePolicy,然后在申请新的web页面时,调用removeAllCacheResponse就可以了。

3. 优化效率

之前在做一个图片的指定颜色替换算法时,经过大师指点,其实已经把效率提高了好几倍,但是后来又站在汇编的角度上,更进一步地把算法优化提升了5,6倍。

优化前的算法:

if ([titles containsObject:areaName]) {
            areaPt.x = [[dic objectForKey:@"x"] floatValue];
            areaPt.y = [[dic objectForKey:@"y"] floatValue];
            areaSize.width = [[dic objectForKey:@"width"] floatValue];
            areaSize.height = [[dic objectForKey:@"height"] floatValue];
            areaColor = [dic objectForKey:@"color"];

            TheColor d;
            const CGFloat *componentsForAreaColor = CGColorGetComponents([self getColor:areaColor].CGColor);
            d.R = componentsForAreaColor[0] * 255.0;// components[0]*alpha
            d.G = componentsForAreaColor[1] * 255.0;
            d.B = componentsForAreaColor[2] * 255.0;

            endPtX = areaPt.x + areaSize.width;
            endPtY = areaPt.y + areaSize.height;

            // change color in (x,y, width,height)
            colColor = [colors objectAtIndex:[titles indexOfObject:areaName]];
            const CGFloat *components = CGColorGetComponents(colColor.CGColor);
            for (unsigned int i=areaPt.y; i<endPtY; i++) {
                for (unsigned int j=areaPt.x; j<endPtX; j++) {
                    index = 4*j + 4*i*imageMap.size.width;//每个像素由四个分量组成所以要乘以4
                    c.R = rawData[index];
                    c.G = rawData[index+1];
                    c.B = rawData[index+2];

                    if ((c.R == d.R)&&(c.G == d.G)&&(c.B == d.B)) {
                        c.R = components[0] * 255.0;// components[0]*alpha
                        c.G = components[1] * 255.0;
                        c.B = components[2] * 255.0;
                        rawData[index] = c.R;
                        rawData[index+1] = c.G;
                        rawData[index+2] = c.B;
                    }
                }
            }
        }

优化后的算法:

if ([titles containsObject:areaName]) {
            areaPt.x = [[dic objectForKey:@"x"] floatValue];
            areaPt.y = [[dic objectForKey:@"y"] floatValue];
            areaSize.width = [[dic objectForKey:@"width"] floatValue];
            areaSize.height = [[dic objectForKey:@"height"] floatValue];
            areaColor = [dic objectForKey:@"color"];

            endPtX = areaPt.x + areaSize.width;
            endPtY = areaPt.y + areaSize.height;
            //用来查找地图区域的颜色
            const CGFloat *componentsForAreaColor = CGColorGetComponents([self getColor:areaColor].CGColor);
            oldColor = 255;
            oldColor = oldColor*256 + (unsigned char)(componentsForAreaColor[2]*255.0);
            oldColor = oldColor*256 + (unsigned char)(componentsForAreaColor[1]*255.0);
            oldColor = oldColor*256 + (unsigned char)(componentsForAreaColor[0]*255.0);
            //要更新成的颜色
            colColor = [colors objectAtIndex:[titles indexOfObject:areaName]];
            const CGFloat *components = CGColorGetComponents(colColor.CGColor);
            newColor = 255;
            newColor = newColor*256 + (unsigned char)(components[2]*255.0);
            newColor = newColor*256 + (unsigned char)(components[1]*255.0);
            newColor = newColor*256 + (unsigned char)(components[0]*255.0);

            for (unsigned int i=areaPt.y; i<endPtY; i++) {
                for (unsigned int j=areaPt.x; j<endPtX; j++) {
                    index = j + i*width;
                    if (rawData[index] == oldColor)
                        rawData[index] = newColor;
                }
            }
        }

原先是直接通过color.R/G/B值对比,需要取3次,并且在对比时,也需要进行&&的判断,这些在汇编中其实是好几行机器代码在执行,所以,改成优化后的算法,其实是比原先快了5,6倍的。直接从1.9秒提高到了0.3秒左右。

时间: 2024-08-03 13:24:20

iOS学习之路:ARC内存清理&amp;缓存清理&amp;效率优化的相关文章

android-Android 如何实现垃圾清理、缓存清理?

问题描述 Android 如何实现垃圾清理.缓存清理? Android 如何实现垃圾清理.缓存清理?要删除什么哪些文件或者要怎么做?在下想写一个一键清理应用,可不知从何下手.谢谢! 解决方案 如果是你自己的应用,把文件放在getCacheDir()中的话,可以删除那些文件.用常用的文件I/O接口. 但是如果是其他应用的文件,没有权限修改或删除的. 解决方案二: android 垃圾收集在不定时间下发生,并由Dalvik虚拟机决定什么时候回收垃圾,显示调用System.gc()可以提醒虚拟机,收集

QQ缓存如何清理?qq缓存清理缓存方法

1.我们先在电脑中打开QQ,然后在登录界面找到导航菜单中的"设置"图标 点击进入 2.现在我们在里面找到"系统设置"再找到"基本设置-->文件管理-"立即清理" 如下图所示. 3.如果你缓存文件比较多扫描缓存文件需要一定的时间. 4.扫描完之后我们就可以直接点击"全部删除"就可以清除缓存了,当然我们也可以勾选上自动清理的qq产生的缓存文件的勾选项,以后就会自动清理了. 5.点击全部删除也需要一些时间,这样像与朋

iOS ARC 内存管理要点

前言 在讨论 ARC 之前,我们需要知道 Objective-C 采用的是引用计数式的内存管理方式,这一方式的特点是: 自己生成的对象自己持有.比如:NSObject * __strong object = [NSObject alloc] init];. 非自己生成的对象自己也能持有.比如:NSMutableArray * __strong array = [NSMutableArray array];. 自己持有的对象不再需要时释放. 非自己持有的对象自己无法释放. 而 ARC 则是帮助我们

Qt 学习之路 2 --- 读书笔记

一.文章来由 来自豆子老师非常好的一本Qt教程,但是只有网络版,所以用这个做笔记了,不动笔墨不读书嘛~~ 二.读书笔记 1.Qt 学习之路 2(2):Qt 简介 1.1 关于 Qt 的一站式解决 Qt 是一个著名的 C++ 应用程序框架.但并不只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI 组件.使用 Qt,在一定程度上你获得的是一个"一站式"的解决方案:不再需要研究 STL,不再需要 C++ 的,不再需要到处去找解析 XML.连接数据库.访问网络的各种第三方库,因为

以实践为起点,设计出重基础的学习之路

在CSDN对我的专访中,我比较全面地阐述了我带领学生开展的以实践为主线的编程学习过程.有人发表评论:"如果你是大学生,我建议你把这篇文章当成垃圾看.大学重点学得应该是基础,不是你那些所谓的为了完成工作而学的项目经验.什么是基础,重点是数学.英语.接下来是计算机组成和操作系统,如果你是计算机系的,C语言必须掌握.谈谈数学重要的原因,以前计算机专业在很多名校都是数学的一个分支,可能刚涉编程你不懂数学的重要性,如果你深入学习数据结构例如的排序的算法时间分析就知道用到了一大堆微积分,还有计算方法,这个反

.Net程序员安卓学习之路5:使用xutils注入View和事件以及图片的显示

原文:.Net程序员安卓学习之路5:使用xutils注入View和事件以及图片的显示 xUtils注入和图片显示 一.xUtils注入 引用官方介绍: ViewUtils模块: •android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定: •新的事件绑定方式,使用混淆工具混淆后仍可正常工作: •目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event.       之前我

C/C++学习之路(二)

                                                   C/C++学习之路(二)           今天我想分享的是关于深拷贝与浅拷贝的区别.               先说下自己的理解吧,浅拷贝,即在定义一个类A,使用类似A obj;  A obj1(obj);或者A obj1 = obj; 时候,由于没有自定义拷贝构造函数,C++编译器自动会产生一个默认的拷贝构造函数.这个默认的拷贝构造函数采用的是"位拷贝"(浅拷贝),而非&quo

C/C++学习之路(一)

C/C++学习之路(一)          今天我想要写的是关于调用构造函数的问题.          首先,我们先来弄懂关于构造函数的定义.在百度百科上,是这么定义的:构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载.          那么,先来看一道题:          当我第一次看到这一道题的时候,我第

大数据学习之路(持续更新中...)

在16年8月份至今,一直在努力学习大数据大数据相关的技术,很想了解众多老司机的学习历程.因为大数据涉及的技术很广需要了解的东西也很多,会让很多新手望而却步.所以,我就在自己学习的过程中总结一下学到的内容以及踩到的一些坑,希望得到老司机的指点和新手的借鉴. 前言 在学习大数据之前,先要了解他解决了什么问题,能给我们带来什么价值.一方面,以前IT行业发展没有那么快,系统的应用也不完善,数据库足够支撑业务系统.但是随着行业的发展,系统运行的时间越来越长,搜集到的数据也越来越多,传统的数据库已经不能支撑