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秒左右。


目录
相关文章
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
70 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
31 3
|
1月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
57 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
22天前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。
|
5月前
|
NoSQL Java Redis
Redis系列学习文章分享---第十八篇(Redis原理篇--网络模型,通讯协议,内存回收)
Redis系列学习文章分享---第十八篇(Redis原理篇--网络模型,通讯协议,内存回收)
85 0
|
3月前
|
缓存 JavaScript
Vue学习之--------编程式路由导航、缓存路由组件、新的钩子函数(4)(2022/9/5)
这篇文章介绍了Vue中编程式路由导航的方法,包括使用`$router.push`、`$router.replace`、`$router.forward`、`$router.back`和`$router.go`进行路由跳转和历史记录操作,以及如何利用`<keep-alive>`组件缓存路由组件,和Vue Router新增的两个生命周期钩子`activated`和`deactivated`的用法及其在项目中的应用和测试结果。
Vue学习之--------编程式路由导航、缓存路由组件、新的钩子函数(4)(2022/9/5)
|
3月前
|
存储 JavaScript 前端开发
学习JavaScript 内存机制
【8月更文挑战第23天】学习JavaScript 内存机制
34 3
|
3月前
|
Swift iOS开发
iOS开发-属性的内存管理
【8月更文挑战第12天】在iOS开发中,属性的内存管理至关重要,直接影响应用性能与稳定性。主要策略包括:`strong`(强引用),不维持对象生命期,可用于解除循环引用;`assign`(赋值),适用于基本数据类型及非指针对象属性;`copy`,复制对象而非引用,确保对象不变性。iOS采用引用计数管理内存,ARC(自动引用计数)自动处理引用增减,简化开发。为避免循环引用,可利用弱引用或Swift中的`[weak self]`。最佳实践包括:选择恰当的内存管理策略、减少不必要的强引用、及时释放不再使用的对象、注意block内存管理,并使用Xcode工具进行内存分析。
|
4月前
|
前端开发 开发工具 Swift
学习iOS开发的准备
准备学习iOS开发?确保有Mac和最新Xcode,先学好编程基础特别是Swift。利用Apple官方文档、在线课程和书籍作为资源。熟悉Xcode及Git,通过实践项目和开源代码积累经验。深研架构模式、核心框架和优化技巧。加入开发者社区,关注行业动态,持续学习。
49 1
|
4月前
|
存储 程序员 C++