分析iOS应用中的内存使用情况

自2007年以来,iPhone的结构或配置都发生了翻天覆地的变化。 内存(RAM)在2018年从128 MB增长到4GB,而存储从4 GB增长到256 GB。 然而,无论我们使用哪种操作系统,在为任何智能手机应用程序开发时,内存仍然是一个值得关注的领域。

在开发适用于iOS应用程序的日志记录框架时,主要基于内存管理,我想到了多个问题:

  • 我的框架使用了多少内存? 我是否在主存储器中保留了太多数据?
  • 是否有内存泄漏?
  • 客户端应用程序是否会由于RAM利用率高而因压力负载而崩溃?
  • iOS中的垃圾收集如何工作? 是否有类似于Java中的GC的GC?

让我们讨论每个问题并解决它们。

我的框架使用了多少内存? 我是否在主存储器中保留了太多数据?

方法1

当我们调试任何iOS应用程序时,XCode会在调试会话中提供CPU,内存,磁盘和网络的使用指标。

要打开,请在左侧窗格中选择Debug Navigator(option)选项。

单击每个参数后,主屏幕将显示详细报告。 这是内存报告的样子:

尽管此报告看起来非常有趣且内容丰富,但它具有误导性并且缺乏详细的内存中断信息。 我们将在后面的部分中看到。

如果您注意到此屏幕右上方有一个小按钮,上面写着“仪器中的配置文件”。 点击那个。 它将打开“乐器”应用程序,该应用程序显示有关应用程序如何使用内存的更好,更详细的视图。 我们稍后会在博客中详细介绍Instruments应用。

方法2

我们也可以选择以Profile模式构建应用程序:

仪器应用会打开,询问我们配置iOS应用所需的方式。 根据需求,有许多选项可供选择。

对于内存使用情况,我们可以选择分配(详细显示内存使用情况)或泄漏(显示内存使用情况与泄漏)

在下一个屏幕上,单击“记录”按钮以开始分析和使用情况。

仪器

如维基百科所述:

Instruments(以前的Xray)是应用程序性能分析器和可视化工具,集成在Xcode 3.0和更高版本的Xcode中。

我们可以使用上述两种方法之一查看Instruments中的内存使用情况。 屏幕将如下所示:

让我们尝试了解此屏幕的主要组成部分:

  1. 该图顶部显示实时内存使用情况。 默认情况下,显示“所有堆”和匿名VM的组合内存使用情况。 您可以通过单击旁边的+号来选择显示其他图形。
  2. 下表中有多列对我们来说非常重要。
  3. 类别定义了内存的使用位置
  4. 永久字节定义了应用当前在内存中保留的字节数。 这在定义我们当前使用的内存量方面很有用。
  5. #Persistent传达了多个持久对象。 这些对象总共消耗了上一列中显示的字节。
  6. #Transient传达了该应用先前保存但现在已释放的对象数。 它们不再被我们的应用程序引用。 在确定内存使用情况时,这可能并不重要,但可以概述应用程序过去如何使用内存。
  7. 总字节数是一个令人误解的数字,将持久性和暂时性字节合并在一起。 仅当您想知道自应用程序运行以来使用了多少内存时,这才有用。
  8. #total是#Persistent和#Transient对象的总和

现在,如前所述,Xcode内存报告具有误导性。 如果我们仔细观察Xcode和Instruments显示的内存使用率值,它们将有很大的不同(一个是47.3MB,另一个是12.14MB)。 另外,我建议您使用实际设备而不是模拟器进行尝试,以获得准确的结果。

现在,让我们尝试了解上图所示的行:

  • 第一行“ 所有堆和匿名VM”是该应用使用的所有内存的总和。
  • 第二和第三行仅是第一行细分为所有堆分配匿名VM。 简而言之,第1行=第2行+第3行
  • 下面的所有行都是第一行的细目分类。 简而言之,第4行+第N行=第1行。
    您可以在那里看到两个类别:
  • malloc —该内存在堆中分配。 总结所有这些将等于所有治疗分配。
  • VM:xxxx —此内存分配为虚拟内存。 总结所有这些将为匿名VM提供价值。

苹果在标题下提供了一个非常不错的有关Instruments的文档:最小化应用程序的内存占用量。 在检测到问题之后,它将进一步减少内存占用。

是否有内存泄漏?

如我们所见,Instruments应用程序还可以帮助我们检测应用程序或集成库中的内存泄漏。 如果我们在Instruments App中选择“泄漏检查”选项,我们将看到以下内容:

在这里,红叉表示内存泄漏,我们甚至可以在下表中查看负责的库。 这是抓住罪魁祸首的好工具。

客户端应用程序是否会由于RAM利用率高而因压力负载而崩溃?

苹果对任何应用程序的内存使用都非常严格。 如果超过内存使用限制,它将强制退出应用程序。 程序员通常无法控制这种行为。 唯一的解决方案是减少平滑功能的使用。

iOS中的垃圾收集如何工作? 是否有类似于Java中的GC的GC?

iOS中的垃圾收集与Java中的垃圾收集不同。 在Java中,我们有一个GC(垃圾收集器)专用于释放内存供其他人使用。 除非GC完成执行,否则内存将无法使用。

在iOS中,自动引用计数用于垃圾收集。 为了简单起见,我将分别使用术语“对象”和“内存块”,尽管它们均表示代码中的某些对象。

  • ARC会统计当前正在引用特定内存块的对象数。
  • 当对象占用/释放内存块的所有权时,它会增加/减少计数。
  • 当引用计数变为零时,ARC将释放内存。

简而言之,如果有任何对象引用内存块/对象,则不会释放它。

有许多与强引用和弱引用相关的场景,您可以在这篇快速文章中介绍:自动引用计数。 本文提供了很好的示例,并进行了适当的解释。