【问题标题】:Memory leak tool tells me zero leaks but memory footprint keeps rising内存泄漏工具告诉我零泄漏,但内存占用不断增加
【发布时间】:2011-01-21 07:25:31
【问题描述】:

我在 SDK 3.2 中为我的应用程序运行了一些内存分析,我使用“泄漏”分析器来查找我所有的内存泄漏,并将它们全部堵住。这是一个滚动视图导航控制器应用程序,其中有图块,您单击一个图块,该图块将转到一个新的图块视图,依此类推,我可以深入许多级别并一直回到顶部,“泄漏”分析器说明了一切很酷。

但是,如果我在“ObjectAlloc”分析器中观察内存占用量,内存占用量会随着我的深入而不断上升(这似乎是合理的),但是当我退出视图时,内存占用量并没有下降我会期待的。

我知道这是对应用程序的模糊描述,但我不能准确地发布数百万行代码 :) 另外应该注意的是,我正在使用 coreData 来存储图像数据,因此数据库正在增长选择更多节点时的大小,不知道是否/何时从内存中释放。

什么给了?

【问题讨论】:

    标签: iphone xcode memory


    【解决方案1】:

    这听起来可能是以下几种情况之一:

    • 释放后内存未归还给操作系统。这是 C 运行时的常见设计。当您进行分配时,C 运行时会为其使用分配更多内存并返回其中的一块供您使用。当您执行 free 时,C 运行时只是将其标记为已释放,但不会将其返回给操作系统。因此,如果泄漏工具正在读取操作系统级别的统计信息而不是 C 运行时统计信息,则泄漏工具将无法报告相应的内存使用量减少。

    • Leak Tool Memory 报告的误导值。泄漏工具可能正在查看与 C 运行时不同的值,并且报告的值会引起您的关注,即使没有任何问题(就像人们尝试在 Windows 中使用任务管理器来检测泄漏并对结果感到非常困惑,因为它对于这项工作来说确实是一个非常糟糕的工具)。

    • 碎片。您的应用程序可能存在内存碎片。也就是说,当您分配,然后解除分配然后分配时,随后尝试的分配大于解除分配留下的“漏洞”。发生这种情况时,您会分割内存空间,留下无法使用的漏洞,阻止大的连续内存块并强制使用越来越多的内存空间,直到内存耗尽。这是一种病理状况,修复通常是特定于应用程序的。

    我认为这三个建议中的第一个很可能是正在发生的事情。

    【讨论】:

      【解决方案2】:

      根据您在 Core Data 中构建对象图的方式,它的内存使用可能会意外增长。

      一个常见的错误是将对象存储在一个复杂且经常出错(加载到内存中)的实体中。每当引用实体的任何其他部分时,这都会导致大 blob 被加载/保留在内存中。随着对象图的增长,它会占用越来越多的内存,除非您主动删除对象然后保存图。

      例如:您有一个包含大量文本信息的人员实体,例如姓名、地址等以及一张大照片。如果您将照片作为人物实体的属性,则只要人物实体出现故障,它就会在内存中。如果您获得属性名称,则照片属性也在内存中。

      为避免这种情况,blob 应位于它们自己的实体中,然后在关系中链接到其他实体。由于关系对象在直接调用之前不会出错,因此它们可以在需要时保持内存不足。

      【讨论】:

      • 我在我的对象图中强调了这样做,所有图像都有自己的实体。但是,如果我要向 coreData 添加许多新项目,包括图像,图像数据由于我刚刚添加它就在内存中,我如何“默认”某些东西以从内存中删除实体?
      • 找到关于“重新故障”的条目,试一试。
      • 不确定这是否适用于您的应用程序,如果适用,您可能已经涵盖了它,但您应该只在需要全尺寸图像时加载全尺寸图像。例如。 tableview 将在行单元格的缩略图中显示许多 meg 的全尺寸图像。它在视觉上看起来很小,但在内存方面,它是巨大的。如果可能的话,您应该创建和存储仅具有足够分辨率的缩略图,以适应它们实际出现的大小。然后只在需要它们的地方准确加载完整的图像,然后立即处理它们。
      • 感谢您的建议,是的,我就是这样做的,我存储了 2 个图像尺寸,一个缩略图和一个全尺寸图像,并且只有在他们查看时才显示全尺寸图像。
      • 原来我的问题与 coredata 无关,它与按钮的 setBackgroundImage 相关,由于某种原因,即使我释放了生活垃圾,它也没有释放我分配给它的图像的内存用户界面图像。看起来其他人也遇到了类似的问题。
      【解决方案3】:

      仅仅因为没有基于引用计数的泄漏,并不意味着您没有在字典“缓存”中填充某些内容并忘记它;这些不会显示为泄漏,因为有对它的有效引用(字典仍然有效,对其所有子项的引用也是如此)。您还需要寻找有效但不必要的对象引用。

      最简单的方法是让它运行太久,然后按类型对对象计数进行排序,看看谁有一个巨大的数字——然后,追踪参考图(在 Obj-C 中可能很难?)。如果 Instruments 不直接这样做,你绝对可以编写一个 DTrace 脚本来这样做。

      【讨论】:

        【解决方案4】:

        重申:

        char *str1 = malloc(1000);
        char *str2 = malloc(1000);
          .
          .
          .
        char *str1000 = malloc(1000);
        

        不是内存泄漏,而是

        char *str1 = malloc(1000);
        char *str1 = malloc(1000);  //Note! No free(str1) in between!
        

        是内存泄漏

        【讨论】:

        • 谢谢,我理解这种区别。我的问题是我正在创建子视图(并观察内存增加)然后正确释放所有视图(但内存占用量不会减少)。我越想越觉得它与向 coreData 添加新信息有关。
        【解决方案5】:

        关于核心数据内存管理的信息是很好的信息,从技术上讲,Arthur Kalliokoski 的回答是一个很好的回答:韭菜和对象分配之间的区别。我在这里的特殊问题与模拟器中按钮上的 setBackgroundImage 明显已知的错误有关,它会造成内存“泄漏”,因为它不会释放 UIImage 的内存。

        【讨论】:

          【解决方案6】:

          您可以拥有一个不断增长的程序而不必泄漏内存。假设您从输入中读取单词并将它们存储在链表中动态分配的内存块中。随着你阅读更多的单词,列表不断增长,但所有内存仍然可以通过列表访问,因此没有内存泄漏。

          【讨论】:

            猜你喜欢
            • 2019-11-11
            • 1970-01-01
            • 2011-05-03
            • 1970-01-01
            • 2016-04-02
            • 1970-01-01
            • 2011-10-23
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多