检测和诊断内存问题

性能是客户端永恒的主题,咱们但愿用户在使用APP时,可以得到极致的性能体验,关注内存占用也正是由于这一点。git

(舒适提示:本片内容来源自WWDC21:Detect and diagnose memory issuesgithub

想了解更多WWDC2021内容的小伙伴,能够阅读我如下文章,欢迎多多交流和指正swift

一文带你读完WWDC21核心(新)技术点xcode

APP终极性能生存指南markdown

  • Faster application activationsapp

    减小APP的内存占用,能够提升APP在后台存活的机会,从而让APP更快的被激活。ide

    设备的内存空间是有限的,监控APP的内存使用状况,可以防止系统为了回收内存而主动终止APP。工具

    这样即便APP在后台运行,也可以保存当前用户的使用状态,从而避免再次从内存加载致使的耗时。oop

  • Responsive experiencepost

    更好的响应速度

    策略性的将APP的内容加载到内存里,可以避免在用户使用APP时,因系统回收内存增长的等待耗时。

  • Complex features

    让用户体验更丰富的功能

    像加载视频、展现动画,这些复杂的功能每每须要占用更多的内存。所以有策略的使用内存,能够避免在用户使用APP的复杂功能时,被系统因内存占用问题而终止。

  • Wider device compatibility

    更好的设备兼容性

    让内存空间不太充足的老设备也能更好的使用APP的功能

内存占用结构

2.png

  • Clean Memory

  • Dirty Memory

    Clean Memory被分配,并写入内容后成为”脏内存“,脏内存包括:

    • 全部的堆分配(malloc)
    • 解码图像缓冲区
    • Frameworks
  • Compressed Memory

    压缩内存特指脏页(Dirty Pages)中暂未被访问的部分(Unaccessed pages),会在访问后解压,成为脏内存。

    (下文会详细介绍脏页(Dirty Pages)的概念)

    注:iOS中没有内存交换(Memory Swap)的概念,你可能在使用Instrument工具时,见到过Swapped字段,实际上所指的是Compressed Memory

内存占用 = Dirty Memory + Compressed Memory

内存画像工具

3.png

  • XCTest

    经过单元测试和U测试中的XCTest来检测开发环境的性能指标

    • XCTest能够测量如下性能指标:

      • 内存使用状况
      • CPU使用
      • 磁盘写入状况
      • 卡顿率
      • 执行时间(完成某一任务所花的所有时间)
      • APP启动时间
    • 经过XCTest检测内存使用状况

      func testSaveMeal() {
      	let app = XCUIApplication()
      	let options = XCTMeasuireOptions()
      	options.invocationOptions = [.manullyStart]
      	measure(metrics: [XCTMemoryMetric(application: app)],
      					options:options) {
      		app.launch()
      		startMeasureing()
      		app.cells.firstMatch.buttons["Save meal"].firstMatch.tap()
      		
      		let savedButton = app.cells.firstMatch.buttons["Saved"].firstMatch
      		XCTAssertTure(savedButton.waitForExistence(timeout: 30))
      	}
      }
      复制代码
    • XCTest在Xcode 13中新增的两项收集性能状况的诊断产物

      开启:enablePerformanceTestsDiagnostics YES

      xcodebuild test
      -project MealPannerApp.xcodeproj
      -scheme PerformanceTests
      -destination platform=iOS,name="iPhone"
      -enablePerformanceTestsDiagnostics YES
      复制代码
      • Ktrace files

        Ktrace file可以打开,并展现如下分析报告:

        • 当卡顿发生时的渲染通道的状态
        • 因主线程阻塞,致使的Hang(APP没法响应用户的输入或者行为超过250ms,即记做一个hang)
      • Memory graphs

        Memory graph展现APP进程的地址空间的快照

        咱们能够生成任务开始(pre_XXX.memgraph)和结束(post_XXX.memgraph)两个时机的内存快照,从而查看这一阶段内存占用的变化。

        4.png

  • MetricKit & Xcode Organizer

    检测线上环境的内存指标

内存问题

  • 内存泄漏(Leaks)

    最多见内存泄漏的缘由的是循环引用

    5.png

    • 经过命令行查看memgraph文件

      6.png

  • 堆大小问题(Heap size issues)

    堆是进程地址空间中储存动态分配的对象的段(section),有策略性的加载和释放内存,能够避免内存峰值太高引起OOM。

    • 堆分配回归(Heap allocation regressions)
    • 碎片化(Fragmentation)

堆分配回归

  • 使用vmmap -summary对memgraph文件进行分析

7.png

  • 咱们主要关心Dirty SizeSwapped Size两列数据

    8.png

  • 对任务开始(pre_XXX.memgraph)和结束(post_XXX.memgraph)两个时机的内存快照进行对比

    9.png

  • 能够在下方看到按类聚合的,各种对象占用内存的大小

    10.png

    从图中能够看到,non-object类型的数据,占用内存约13M。在Swift中,non-object一般表明原始分配字节(raw malloced bytes)

  • 打印memgraph文件中,类型为non-object且占用内存超过500k的对象

    11.png

  • 打印对象的引用树

    12.png

  • 能够经过malloc_history -fullStacks打印对象的分配调用栈

    13.png

  • 当不肯定是哪一个对象有问题时,能够经过leaks --referenceTree,自顶向下打印进程的全部内存中最可疑的对象

    14.png

    • 能够经过--groupByType参数,按type聚合简化打印结果。

    15.png

碎片化

先介绍两个概念:页和”脏页“

  • 页(Pages):是最小的独立的内存单元
  • 一旦页中写入任何数据,都会使整页变成”脏页“

16.png

当内存准备写入新的数据时,系统会优先尝试使用脏页中的空闲内存,而立即将分配的内存过大时,即便空闲内存的总大小足够,但其并非一段连续的内存空间,仍会开辟一个新的脏页去写入这些数据。

这些没法被使用的空闲内存就是”碎片化内存“

再例如如下这种状况:咱们分配的对象总共使用了4个页,但每一个页的占用空间只占50%。

25.png

当咱们释放这些对象后,这些4个脏页的内存空间仍有50%的碎片化内存。

最理想化的状态应该将全部的分配的对象放在两页,以下图:

18.png

这样一旦释放这些对象时,仅会留有两个脏页,而且不存在碎片化内存。

19.png

  • 咱们的目标:

    • 让分配的对象尽量连续且拥有一样的生命周期
    • 碎片化率保持在25%如下
    • 使用自动释放池
    • 特别注意长时间运行的进程
  • vmmap -summary xx.memgraph查看碎片化内存状况

    20.png

    • DefaultMallocZone

      平时开发者只须要关注这部分的内存空间,由于这是咱们进行堆分配默认结束的地方

    • MallocStackLoggingLiteZone

      这个空间是全部堆分配结束的地方

  • 使用Instruments工具中的Allocations track查看内存状况

    21.png

    其中的Destroyed和Persisted分别对应上面所描述的内存释放后的空闲内存(free memory)和仍未释放的内存(remaining objects)

    22.png

回顾下咱们的整体排查流程:

23.png

更多WWDC有关性能的Session

iOS memory deep dive WWDC18

Getting started with Instruments WWDC19

Understand and eliminate hangs from your apps WWDC21

相关文章
相关标签/搜索