zoukankan      html  css  js  c++  java
  • iOS高级教程:处理1000张图片的内存优化

    一、项目需求

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

     

    二、内存分析,非优化

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

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

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

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

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

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

    三优化后的内存使用

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

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

    优化后的,内存使用情况 

     可用内存不再明显的减少

    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自动引用计数)为推荐的替代技术。

  • 相关阅读:
    83. Remove Duplicates from Sorted List
    35. Search Insert Position
    96. Unique Binary Search Trees
    94. Binary Tree Inorder Traversal
    117. Populating Next Right Pointers in Each Node II
    116. Populating Next Right Pointers in Each Node
    111. Minimum Depth of Binary Tree
    169. Majority Element
    171. Excel Sheet Column Number
    190. Reverse Bits
  • 原文地址:https://www.cnblogs.com/fengmin/p/4973539.html
Copyright © 2011-2022 走看看