使用仪器工作通过低内存警告
我正试图通过使用仪器的一些低内存条件。 即使Allocations显示All Allocations大约为3 MB,总体字节数为34 MB,我也可以在Physical Memory Free监视器中查看内存消耗,下降到几MB。
我已经开始遇到崩溃,因为我把一些操作移动到一个NSOperationQueue单独的线程。 但是在改变之前我没有使用仪器。 不过,我敢打赌,我做了一些我可以撤消的事情来阻止事故的发生。
顺便说一句,没有仪器或debugging器连接,它是更加稳定。
我有泄漏到几乎没有(可能在崩溃前最多100个字节)。
当我看到分配时,我只看到非常原始的对象。 而且它报告的总内存也非常低。 所以我不能看到我的应用程序如何导致这些低内存警告。
当我从一开始就看堆射击时,在基线和所有堆增长值的总和之间,我看不到超过3 MB。
我应该看什么来找出问题所在? 我可以将它隔离到我的一个视图控制器实例,例如? 或者对我的其他实例之一?
我做了什么:我closures了设备,然后重新启动,这样做有了很大的改进。 仪器不报告低内存警告。 另外,我注意到启动时的物理可用内存在重新启动之前只有大约7 MB,重新启动后大约60 MB。
但是,我看到物理可用内存的规模(周期性)下降,从43 MB降至6 MB(然后又回升至43 MB)。 我想知道是什么造成的。 我没有任何计时器在这个应用程序中运行。 (我有一些performSelector:afterDelay:,但这些testing过程中不活动。)
我没有使用ARC。
分配和泄漏工具只显示对象实际采取的内容,而不显示其下层的非对象结构(支持存储)正在采取的行动。 例如,对于UIImages,它会显示你有几个分配的字节。 这是因为UIImage
对象只占用这些字节,而实际上包含图像数据的CGImageRef
不是一个对象,在这些工具中并没有考虑到它。
如果您还没有这样做,请尝试在运行分配工具的同时运行VM跟踪器 。 它会给你一个正在分配的types内存的想法。 对于iOS而言,本仪器显示的“ 脏内存 ”通常会触发内存警告。 脏内存是不能被VM系统自动丢弃的内存。 如果你看到很多CGImages,图片可能是你的问题。
另一个重要的概念是遗弃的记忆 这是分配的内存,它仍然在某处引用(而不是泄漏),但没有使用。 这种types的内存的一个例子是某种types的caching,它不会在内存警告时释放。 find这个的方法是使用堆分析。 按分配仪器的“Mark Heap”button,做一些操作,返回到应用程序中的前一个点,然后再次按“Mark Heap”。 第二堆照片应该显示在这两个时刻之间分配了什么新物体,并且可能揭示出这个谜团。 您也可以重复模拟内存警告的操作,以查看该行为是否改变。
最后,我build议你阅读这篇文章,它解释了所有这些工作: http : //liam.flookes.com/wp/2012/05/03/finding-ios-memory/ 。
VM Tracker的物理内存与“Allocations”分配的内存之间的区别在于这些工具的主要区别:
-
Allocations通过在分配内存的函数(
malloc
,NSAllocateObject
,…)中安装tap来跟踪你的应用程序的function。 这种方法可以得到关于每个分配的非常精确的信息,比如代码(堆栈)中的位置,数量,时间,types。 缺点是如果你不跟踪每一个函数(比如vm_allocate
)以某种方式分配内存,那么你就会失去这个信息。 -
VM Tracker定期对系统的虚拟内存进行采样 。 这是一个不太精确的方法,因为它只是给你一个当前状态的总体看法。 它的运行频率很低(通常是每三秒钟一次),你不知道这个状态是如何达到的。
一个不可见的分配的罪魁祸首是CoreGraphics:它解压缩图像,绘制位图上下文等时使用大量的内存。 这个记忆通常在分配工具中是不可见的。 因此,如果您的应用处理大量图像,则可能会发现物理内存量与总体分配大小之间存在很大差异。
物理内存中的尖峰可能是由于大图像被解压缩,缩小,然后仅用于某些视图或图层内容的屏幕分辨率。 所有这些都可能在UIKit
自动发生,而不涉及您的代码。
我有泄漏到几乎没有(可能在崩溃前最多100个字节)。
根据我的经验,很小的泄漏也是“危险的”标志。 事实上,我从来没有见过大于4K的泄漏,而我通常看到的泄漏是几百个字节。 尽pipe如此,他们通常“躲”在自己身后的是一个更大的记忆。
所以,我的第一个build议是:摆脱这些泄漏,即使它们看起来很小而且微不足道 – 它们不是。
我已经开始遇到崩溃,因为我把一些操作移动到一个NSOperationQueue单独的线程。
你有没有机会转移到线程是负责脉冲高峰? 它能一次产生多于一次吗?
至于高峰,我看到两种方式你可以去做:
-
使用仪器中的时间分析器,并尝试了解执行哪些代码,同时看到峰值上升;
-
有select地注释掉你的代码的一部分(我的意思是:你的应用程序的整个部分 – 例如,用一个基本的/空的
UIViewController
replace一个“真正的”控制器等),看看你是否可以通过这种方式识别罪魁祸首。
我从来没有见过这样的脉动行为,所以我认为这取决于您的应用程序或您的设备上。 你尝试过不同的设备吗? 模拟器中会发生什么(你看到峰值)?
当我阅读你的文字时,我的印象是你可能有一些隐藏的泄漏。 我可能是错的,但是,你100%肯定你有检查所有泄漏?
我记得我几个月前做的一个特别的项目,我有同样的问题,仪器也没有泄漏。 我的记忆不断成长,我得到记忆警告…我开始login一些重要的dealloc方法。 而且我看到有些对象,子视图(UIView)在“泄漏”。 但是,他们没有被仪器看到,因为他们仍然坚持主观观点。
希望这是有帮助的。
在分配工具中,确保您有“仅跟踪活动分配”选项。 见下面的图片。 我认为这样可以更容易地看到实际发生的情况。
-
你在项目上运行分析吗? 如果有任何分析警告,请先解决。
-
你使用任何CoreFoundation的东西? 一些CF方法有…奇怪的…与ObjC运行时间和内存pipe理的交互(他们不应该这样做,AFAICS,但我已经看到一些奇怪的行为与低级图像和AV操作像mem一样在核心应用程序之外使用 – 也许操作系统调用被苹果使用?)
…注:在以前的iOS版本中,也有一些在苹果的CF方法中存在mem漏洞。 IIRC的最后一个在iOS 5.0中修复。
- (StackOverflow的分析器糟透了:我键入“3”而不是“1”)你是否正在做大量的/大型CALayer实例(或UIView的CG *方法,例如UIView中的自定义drawRect方法?
…注意:在CF库或苹果窗口系统中,当您尝试使用最初在CF库中生成的图像数据时,我已经看到了上述由2和3引起的确切行为,或者find了进入CALayers的方式。
似乎工具不正确地跟踪CA / CG系统内的内存使用情况; 这个区域有点复杂,因为苹果正在CPU和GPU内存之间来回拖曳,但令人失望的是,使用时似乎只是“消失”了!
最后的想法(4. – 但是SO不会让我input) – 你使用仪器的隐形RHS吗?
苹果硬编码的仪器总是禁用自己每次运行它(所以你必须保持手动打开它)。 这很愚蠢,因为一些核心信息只存在于RHS栏中。 但是我曾经和几个甚至不知道它存在的人合作:)