转载请保留以下原文链接:

http://my.oschina.net/taptale/blog/91894

一、项目需求

在实际项目中,用户在上传图片时,有时会一次性上传大量的图片。在上传图片前,我们要进行一系列操作,比如:旋转图片为正确方向,压缩图片等,这些操作需要将图片加载到内存中,下面对内存的使用做详细分析.

二、内存分析,非优化

我在测试项目中,重复加载了一张图片1000次,首先加载图片到内存,然后进行压缩操作,释放内存

01 for (int i = 0; i <= 1000; i ++) {
02  
03        //1.首先我们获取到需要处理的图片资源的路径
04  
05         NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"PNG"];
06  
07         //2.将图片加载到内存中,我们使用了alloc关键字,在使用完后,可以手动快速释放掉内存
08  
09         UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath];
10  
11        //3.这一步我们将图片进行了压缩,并得到一个autorelease类型实例
12  
13         UIImage *image2 = [image imageByScalingAndCroppingForSize:CGSizeMake(480, 320)];
14  
15        //4.释放掉2步骤的内存
16  
17         [image release];
18  
19     }

上面的代码看起来没有任何问题,可以说是一种标准的代码写法,在每一步骤中都对内存做了小心的处理,我们来看一下,实际的内存使用情况:

 
在上图中可以看到,我们的操作在没有任何问题的情况下,在加载大量图片时,还是会造成内存的剧减

可以看到自动释放内存时,图片占用的内存并没有立即释放掉

这些资源没有立即释放的资源,占用了宝贵的内存资源,最终使程序被kill

三优化后的内存使用

上面程序被kill,是因为程序的内存使用问题,在上面的代码中,我们每一步都对内存做了非常小心的处理,但是在加载大量的图片时,还是会出现问题。其根本原因就是autorelease惹的祸,autorelease自动释放内存,并不会立即把内存释放掉,而是要等到下一个事件周期才会释放掉。问题是一些资源我们不得不使用autorelease类型,比如作为函数的返回值,而且系统api及项目是的大部分也都是这么做的,如果全都依靠我们手动释放很容易造成内存泄漏。

记住:NSAutoreleasePool里面的维护了一个NSMutableArray数组,所有标记为autorelease的对象都会被添加都该数组中。只有当pool对象被drain的时候,才会去遍历该数组,若retainCount为0则释放内存,不为零就发生内存泄露!OC已经为我们建立一个pool对象,但是该pool对象需要比较久的时间才能drain掉,因此在一些遍历处理的场景中,需要我们手动去建立pool对象,并手动drain掉。

01 for (int i = 0; i <= 1000; i ++) {
02  
03        //创建一个自动释放池
04  
05         NSAutoreleasePool *pool = [NSAutoreleasePool new];
06  
07         NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"PNG"];
08  
09         UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath];
10  
11         UIImage *image2 = [image imageByScalingAndCroppingForSize:CGSizeMake(480, 320)];
12  
13         [image release];
14  
15        //将自动释放池内存释放,它会同时释放掉上面代码中产生的临时变量image2
16  
17         [pool drain];
18  
19     }

优化后的,内存使用情况

可用内存不再明显的减少

CGImage及UIImage的数据由原来的220多减少到6-7个

可以看到使用了 NSAutoreleasePool后,加载大量图片的时候内存也不会出现问题

四、自动释放池概述

(1)自动释放池被置于一个堆栈中,虽然它们通常被称为被“嵌套”的。当您创建一个新的自动释放池时,它被添加到堆栈的顶部。当自动释放池被回收时,它们从堆栈中被删除。当一个对象收到送autorelease消息时,它被添加到当前线程的目前处于栈顶的自动释放池中。你不能向自动释放池发送autorelease或retain消息。Application Kit会在一个事件周期(或事件循环迭代)的开端—比如鼠标按下事件—自动创建一个自动释放池,并且在事件周期的结尾释放它,因此您的代码通常不必关心。 有三种情况您应该使用您自己的自动释放池:

  • 如果您正在编写一个不是基于Application Kit的程序,比如命令行工具,则没有对自动释放池的内置支持;您必须自己创建它们。

  • 如果您生成了一个从属线程,则一旦该线程开始执行,您必须立即创建您自己的自动释放池;否则,您将会泄漏对象。

  • 如果您编写了一个循环,其中创建了许多临时对象,您可以在循环内部创建一个自动释放池,以便在下次迭代之前销毁这些
     对象。这可以帮助减少应用程序的最大内存占用量。

(2) release和drain之间的差异

在引用计数环境下,release和drain一样,会直接自动释放池l对象。

在GC(垃圾回收)环境下,release是一个no-op(空操作),drain会触发垃圾回收(如果自上次垃圾回收以来分配的内存大于当前的阈值)。

通常情况下,您都应该使用drain而不是使用release来销毁自动释放池。

-drain方法只适用于Mac OS X10.4(Tiger)及更高版本。

在OS X Mountain Lion v10.8操作系统下,GC(垃圾回收)将被废弃,ARC(Automatic Reference Counting自动引用计数)为推荐的替代技术。

【转】IOS高级教程1:处理1000张图片的内存优化的更多相关文章

  1. iOS高级教程:处理1000张图片的内存优化

    一.项目需求 在实际项目中,用户在上传图片时,有时会一次性上传大量的图片.在上传图片前,我们要进行一系列操作,比如:旋转图片为正确方向,压缩图片等,这些操作需要将图片加载到内存中,下面对内存的使用做详 ...

  2. ios cocopods 安装使用及高级教程

    CocoaPods简介 每种语言发展到一个阶段,就会出现相应的依赖管理工具,例如Java语言的Maven,nodejs的npm.随着iOS开发者的增多,业界也出现了为iOS程序提供依赖管理的工具,它的 ...

  3. [[iso教程]] 《4个月ios实体教程》全网最新、最全ios视频教程

    全网最新.最全ios视频教程 内容简介 <ios实体教程>主要介绍如何使用iOS提供的强大工具集创建iOS应用.全视频对iOS操作系统做了全面的介绍,首先讲解如何构建应用程序的用户界面,涵 ...

  4. Siki_Unity_2-9_C#高级教程(未完)

    Unity 2-9 C#高级教程 任务1:字符串和正则表达式任务1-1&1-2:字符串类string System.String类(string为别名) 注:string创建的字符串是不可变的 ...

  5. Unity3D for iOS初级教程:Part 2/3

    转自Unity3D for iOS 这篇文章还可以在这里找到 英语 Learn how to use Unity to make a simple 3D iOS game! 这篇教材是来自教程团队成员 ...

  6. Pandas之:Pandas高级教程以铁达尼号真实数据为例

    Pandas之:Pandas高级教程以铁达尼号真实数据为例 目录 简介 读写文件 DF的选择 选择列数据 选择行数据 同时选择行和列 使用plots作图 使用现有的列创建新的列 进行统计 DF重组 简 ...

  7. 【读书笔记】.Net并行编程高级教程(二)-- 任务并行

    前面一篇提到例子都是数据并行,但这并不是并行化的唯一形式,在.Net4之前,必须要创建多个线程或者线程池来利用多核技术.现在只需要使用新的Task实例就可以通过更简单的代码解决命令式任务并行问题. 1 ...

  8. 【读书笔记】.Net并行编程高级教程--Parallel

    一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控>这本书中也多次提到并发,不管是计算机 ...

  9. fir.im Weekly - 给女朋友的 iOS 开发教程

    俗话说:技多不压身,功到自然成.本期 fir.im Weekly 收集的热度资源,大部分关于Android.iOS 开发工具和源码,还有一些有关设计的 Tips ,希望对你有帮助. 给女朋友的 iOS ...

随机推荐

  1. Asphyre 更名pxl 终于全面支持跨平台了.Delphi饭们 激动了吧.

    Asphyre We are happy to announce the official release of our latest framework Pascal eXtended Librar ...

  2. Android 布局之LinearLayout

    Android 布局之LinearLayout 1 LinearLayout简介 LinearLayout是线程布局.它包括2个方向(android:orientation):“水平”(horizon ...

  3. 基于openssl的单向和双向认证

    1.前言 最近工作涉及到https,需要修改nginx的openssl模块,引入keyless方案.关于keyless可以参考CloudFlare的官方博客: https://blog.cloudfl ...

  4. Android SQLite的ORM接口实现(一)---findAll和find的实现

    最近在看Android的ORM数据库框架LitePal,就想到可以利用原生的SQLite来实现和LitePal类似的ORM接口实现. LitePal有一个接口是这样的: List<Status& ...

  5. 探秘空值位图掩码(NULL bitmap mask)

    这篇文章我想谈下空值位图掩码(NULL bitmap mask) ,并揭开它的神秘面纱.空值位图掩码是在存储引擎层为列是否存储NULL值进行编码.它是一个简单的位图掩码,如果值是1的话,表示这列有NU ...

  6. SQL Server 2005 Service Broker

    一.引言 SQL Server 2005 的一个主要成就是可以实现可靠.可扩展且功能完善的数据库应用程序.与 .NET Framework 2.0 公共语言运行库 (CLR) 的集成使开发人员可以将重 ...

  7. 快捷获取浏览器(navigator对象)的全部属性

    理论:     navigator对象包含关于web浏览器的信息,浏览器的类型,版本信息都可以从该对象获取. 属性 说明 appCodeName 浏览器代码说明 appName 浏览器名称 appVe ...

  8. C# 之屏幕找图

    引言 最近,由于工作上的某些原因,又要写类似于外挂的程序,又要用到一个屏幕找图功能,很多程序(eg:按键精灵)都提供了类似的功能,其实在这之前,我也查找过很多类似的C#方法,因为之前有一个试过没有用得 ...

  9. 重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知

    [源码下载] 重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 后台任务 推送通 ...

  10. 与众不同 windows phone (37) - 8.0 文件系统: StorageFolder, StorageFile, 通过 Uri 引用文件, 获取 SD 卡中的文件

    [源码下载] 与众不同 windows phone (37) - 8.0 文件系统: StorageFolder, StorageFile, 通过 Uri 引用文件, 获取 SD 卡中的文件 作者:w ...