最近项目中遇到了很多关于内存泄露和缓存清理的问题,尤其是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秒左右。