使用工具来解决低内存警告问题

11

我正在使用Instruments来处理一些低内存条件。我可以看到“物理内存空闲”监视器中的内存消耗下降到几MB,尽管Allocations显示所有分配约为3MB,总字节数为34MB。

自从将一些操作移动到一个带有NSOperationQueue的单独线程后,我开始遇到崩溃。但是在更改之前我没有使用Instruments。尽管如此,我相信我做了一些可以撤销的事情来阻止崩溃。

顺便说一句,没有连接Instruments或调试器时,应用程序要稳定得多。

我已经将泄漏减少到几乎没有(可能是崩溃前最多一百个字节)。

当我查看Allocations时,我只看到了非常基本的对象。而且它报告的总内存也非常低。所以我看不出我的应用程序是如何引起这些低内存警告的。

当我从启动时查看Heap Shots时,我没有看到超过3MB的内容,介于基线和所有堆增长值之间。

我应该查找什么来找到问题所在?例如,可以将其隔离为我的某个视图控制器实例或其他实例之一吗?

我已经做了以下操作: 我关闭并重新打开设备,这有了显着的改进。Instruments没有报告低内存警告。此外,我注意到重新启动之前启动时的“物理空闲内存”仅约为7MB,重新启动后约为60MB。

然而,我看到了一个非常定期(周期性)的“物理空闲内存”下降,从43MB降至6MB(然后再次上升到43MB)。我想知道是什么导致了这个问题。在这个应用程序中我没有运行任何定时器(timer)。 (我确实有一些performSelector:afterDelay:但在这些测试期间它们不活跃。)

我没有使用ARC。


你找到这个问题的解决方案/解释了吗?我也遇到了类似的问题。 - mm24
6个回答

19
AllocationsLeaks工具只会显示对象实际占用的内存大小,但不会显示它们底层非对象结构(即后备存储)占用的内存大小。例如,对于UIImages,它将显示你已分配了几个字节。这是因为UIImage对象只占用这些字节,但包含图像数据的CGImageRef不是一个对象,并且这些工具中不计算其占用情况。
如果您还没有这样做,请尝试同时运行VM Tracker和allocations工具。它将为您提供正在分配的内存类型的概念。对于iOS,此工具显示的“Dirty Memory”通常会触发内存警告。脏内存是指VM系统无法自动丢弃的内存。如果您看到大量的CGImages,图像可能是问题所在。
另一个重要的概念是abandoned memory。这是已分配的内存,仍然在某个地方引用(因此不是泄漏),但未使用。这种类型的内存示例是某种缓存,该缓存在发生内存警告时不释放。查找此信息的方法是使用堆栈分析。按allocations工具的“Mark Heap”按钮,在执行一些操作后,返回到应用程序的先前点并再次按“Mark Heap”。第二个堆栈快照应显示在这两个时刻之间分配的新对象,并可能阐明这个谜团。您还可以重复模拟内存警告执行该操作,以查看此行为是否发生变化。
最后,我建议您阅读这篇文章,它解释了所有这些工作原理: http://liam.flookes.com/wp/2012/05/03/finding-ios-memory/

9
从VM Tracker和“Allocations”分配的物理内存之间的差异是由于这些工具工作方式的主要差异:
- “Allocations”通过在分配内存的函数(malloc,NSAllocateObject等)中安装一个触发器来跟踪您的应用程序的操作。此方法提供有关每个分配的精确信息,例如代码位置(堆栈),数量,时间和类型。缺点是,如果您没有跟踪每个分配内存的函数(例如vm_allocate),则会丢失此信息。
- VM Tracker定期对系统虚拟内存状态进行采样。这是一种不太精确的方法,因为它只给您提供当前状态的整体视图。它以低频率运行(通常是每三秒钟),您无法了解达到此状态的方式。
另外,CoreGraphics是隐形分配的罪魁祸首:当解压缩图像,绘制位图上下文等时,它使用大量内存。在“Allocations”仪器中,这种内存通常是不可见的。因此,如果您的应用程序处理大量图像,则物理内存和总分配大小之间可能存在很大差异。
物理内存中的峰值可能来自于将大型图像解压缩,缩小然后仅在某些视图或层的内容中使用屏幕分辨率。所有这些都可能在UIKit中自动发生,而不需要您的代码参与。

我仍然不清楚如何使用工具来跟踪内存问题,考虑到我已经尝试过的内容。虚拟机显示一条平直的线,没有任何活动可以与物理内存空闲的定期下降相对应。我尝试了其他几个工具(没有一个叫做“CoreGraphics”),但是仍然看不到与内存使用脉冲的相关性。我想将其与进程绑定,但不知道是否可以或如何实现。顺便说一下,我关闭了位置服务,但这也没有对脉冲产生任何显着影响。 - Jim

4
我已经将内存泄漏几乎降至零(在崩溃前最多只有一百字节)。
根据我的经验,即使是非常小的内存泄漏也是“危险”的信号。实际上,我从未见过大于4K的泄漏,我通常看到的泄漏是几百个字节。尽管如此,它们通常会“隐藏”更多丢失的内存。
因此,我的第一个建议是:摆脱这些泄漏,即使它们似乎很小和不重要 -- 它们并不是。
我把一些操作移到了NSOperationQueue中的单独线程中,但是开始经历崩溃。
可能你移动到线程中的操作是造成脉冲高峰的罪魁祸首吗?它可能同时生成多次吗?
至于高峰,我看到两种方法可以解决它们:
1.使用Instruments中的Time Profiler并尝试了解看到高峰上升时正在执行的代码;
2.选择性地注释掉您的代码部分(我指:整个应用程序的部分 - 例如,用基本/空的UIViewController替换“真正”的控制器等),并查看是否可以通过这种方式确定罪魁祸首。
我从未见过这样的脉冲行为,因此我认为它取决于您的应用程序或设备。您是否尝试过其他设备?模拟器中会发生什么(您是否看到高峰)?

2
在"分配工具"中,请确保您已选中"仅跟踪活动分配"。请参见下面的图片。我认为这可以更容易地看到实际发生的情况。

2
  1. 你是否对项目进行了分析?如果有任何分析警告,请先修复它们。

  2. 你是否使用了任何CoreFoundation相关内容?其中一些CF方法与ObjC运行时和内存管理的交互有些奇怪(在我看来,它们不应该出现问题,但我曾经在低级别的图像和AV操作中看到一些奇怪的行为,似乎内存正在被用于核心应用程序进程之外 - 也许是由Apple使用的OS调用?)

... 注意:在之前版本的iOS中,Apple的CF方法中曾经出现过一些内存泄漏问题。我IRC最后一个问题在iOS 5.0中得到了修复。

  1. (StackOVerflow的解析器很糟糕:我输入的是“3”而不是“1”)你是否正在处理大量/大尺寸的CALayer实例(或具有CG *方法的UIView,例如UIView中的自定义drawRect方法?)

... 注意:我曾经因2和3导致了你描述的确切行为,在CF库中或者在苹果窗口系统中,当其尝试使用最初在CF库中生成的图像数据或进入CALayers的图像数据时发生了这种情况。

看起来Instruments无法正确追踪CA/CG系统内存使用情况。这个区域有点复杂,因为苹果公司在CPU和GPU RAM之间来回移动,但令人失望的是,当内存明显仍在被使用时,内存使用量似乎只是“消失”了!


最后一个想法(4. - 但SO不允许我输入)- 你是否正在使用Instruments的不可见右侧?

Apple强制使Instruments每次运行时都自动关闭(因此您必须手动打开它)。这很愚蠢,因为一些核心信息仅存在于右侧栏中。但是我曾经与几个人共事,他们甚至不知道它的存在:)


2
当我阅读您的文本时,我有一种印象,认为您可能存在一些隐藏的泄漏。我可能是错的,但您是否100%确定已经检查了所有的泄漏?
我记得几个月前我正在做一个特定的项目,我遇到了同样的问题,在Instruments中没有泄漏。我的内存不断增长,我收到了内存警告...我开始记录一些重要的dealloc方法。我发现一些对象、子视图(UIView)在“泄漏”。但它们没有被Instruments看到,因为它们仍然附加在主视图上。
希望这对您有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接