【问题标题】:Memory warning and crash: how to handle it内存警告和崩溃:如何处理
【发布时间】:2011-01-23 14:07:12
【问题描述】:

我使用仪器来查看内存泄漏。至少在我不断浏览幻灯片/页面(在 UIScrollView 内)的一种情况下,我看不到任何内存泄漏。使用工具 - 在“分配寿命”下,我切换到查看“已创建和仍然生活”,并看到整个内存大约 1.17MB。我认为这意味着我的应用程序仅使用了这么多实际内存,其余部分正在被正确回收。

然而,在浏览了 100 多页之后,我收到了内存警告,然后我的几个视图被卸载,导致整个应用程序崩溃。

如果我没有使用大量内存并且没有内存泄漏,为什么我会收到内存警告?由于没有什么我可以真正释放的,我看不到避免崩溃的方法。任何人都经历过这种情况或知道我该怎么办?我是否误解了 Instruments 的任何内容?非常感谢您的任何评论。

【问题讨论】:

  • 仍然没有线索。也许“仪器”没有正确报告我可能遇到的一些泄漏。还有其他更可靠的内存泄漏查找工具吗?

标签: iphone cocoa-touch memory-leaks


【解决方案1】:

The documentation says:

如果匹配的图像对象尚未在缓存中,则此方法从指定文件加载图像数据,将其缓存,然后返回结果对象。

因此,您使用imageNamed: 加载的每张图片在您释放最后一次所有权后都将继续存在于缓存中。

Instruments 不会将此显示为泄漏,因为严格来说,它不是泄漏:某些 (UIImage) 仍然知道这些图像。泄漏工具只会显示存在但一无所知的对象的泄漏。

不过,您仍然可以在 Instruments 中看到这一点。

  1. 在跟踪文档中选择 ObjectAlloc 工具,并按当前计数或当前总大小对类列表进行排序。你会看到大部分内存都被 UIImage 对象占用了。

  2. 如果您将鼠标悬停在 UIImage 行的类名列上,您将看到一个➲(转到 iTunes-Store)图标;如果单击它,您将看到所有 UIImage 实例的列表。

  3. 然后,如果您将鼠标悬停在实例行的地址列上,您将看到相同的按钮;这一次,点击它会带您进入该地址的历史记录,包括该地址对象的所有创建、保留、释放和释放。

    在这里,您可以看到图像的分配(在 UIImage 类中,由您向下排列几个堆栈帧)、保留(由您)和释放(由您)。您还可以看到它还没有被 UIImage 释放——+[UIImage imageNamed:] 缓存仍然拥有该图像,因此是“泄漏”。

如果您不希望图像像那样堆积,请使用imageWithContentsOfFile:the -[NSBundle pathForResource:ofType:] method 自行加载。

更新:我已经读到自 iOS 3 以来,UIImage 将在(至少某些)低内存情况下清除其缓存,因此这不应该像它那样成为“泄漏”以前是。您可能仍会看到内存堆积,但最终您应该会看到堆积崩溃。如果您仍然看到内存堆积并且可以证明这是 Apple 的错,您应该记录您的证据并file a bug

【讨论】:

    【解决方案2】:

    您是否将NSZombieEnabled 环境变量设置为yes?它将导致释放的对象保留在内存中,从而不允许您重新获得内存。因此,如果处于活动状态,请尝试禁用它。

    【讨论】:

      【解决方案3】:

      您是否检查过您释放了所有 IBOutlet 对象? 在您的 dealloc 上,您应该释放对象中的任何 IBOutlet 对象,即使它们没有合成方法。

      我们有一个类似的问题,我们已经解决了它发布所有的 IBOutlets。

      Check this answer in Stack Overflow

      【讨论】:

        【解决方案4】:

        如果您只有 3 页,我了解您正在重复使用某些项目。

        如果没有其他代码,很难说出哪里出了问题,但也许您应该在创建新对象之前尝试释放卡通对象。

        试试这样的:

        IImage *image = [UIImage imageNamed:imageFile];
        
        if (cartoon!=nil)
            [cartoon release];
        
        cartoon = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 40.0, 320, 280)];
        
        cartoon.image = image ;
        cartoon.backgroundColor = [UIColor brownColor];
        

        【讨论】:

          【解决方案5】:

          找到问题的根源。在下面的sn-p

          UIImage *image = [UIImage imageNamed:imageFile];
          
          cartoon = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 40.0, 320, 280)];
          
          cartoon.image = image ;
          cartoon.backgroundColor = [UIColor brownColor];
          

          我在每个页面上有 100 张图片和一些文字,用户可以通过手指轻弹来滚动浏览它们(就像他们在 iphone 的照片应用程序中所做的那样)。我只在 UIScrollView 中创建 3 个页面并加载/卸载(并释放)我明确分配的所有内容。因此,在发布卡通片时,我只是发布卡通片 UIImageView 而不是 UIImage 认为它会自动发布。

          但似乎它没有被自动释放。我的应用收到内存警告(我不采取任何措施),操作系统卸载导致崩溃的视图。

          当我注释掉这两行(下面修改了 sn-p)时,问题就消失了。没有警告没有崩溃。

              //UIImage *image = [UIImage imageNamed:imageFile];
          
          cartoon = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 40.0, 320, 280)];
          
          //cartoon.image = image ;
          cartoon.backgroundColor = [UIColor brownColor];
          

          有谁知道如何解决这个问题?有没有办法在警告发生时强制从 UIImage 释放内存?

          【讨论】:

          • 它正在自动发布。它只是也归其他东西所有。您可以通过查看 Instruments 中的各个 UIImage 实例来了解这一点。
          猜你喜欢
          • 2011-10-15
          • 2013-08-02
          • 1970-01-01
          • 2013-04-27
          • 1970-01-01
          • 1970-01-01
          • 2017-11-15
          • 2012-10-20
          • 2011-09-12
          相关资源
          最近更新 更多