0x1 前言

在上一篇文章iOS 内存优化之东西介绍中提到利用leaks东西进行排查内存问题的最佳实践方案,本篇文章是对其的弥补,这儿将讲述录制UITest和主动导出内存图进程的详细实践。

这儿对导出内存图的办法提供两种方案

1.xcodebuild test + 功能测验(XCTMemoryMetric)

2.xcodebuild test + expect + lldb + leaks

扼要的说一下这两种方案的区别:

第一种方案来自2021-WWDC中的Detect and diagnose memory issues的演示。其特点是对测验用例设置的均匀内存值超出预设值时,触发测验用例履行失利,便会主动导出内存图。可是该方案运用xcodebuild运转时似乎存在bug,详细情况后面会细说。

第二种方案来自2021年时,刚研究leaks东西时发生的一个主意,是否能够经过录制UI测验用例,跑完事务场景后主动导出内存图?然后就一顿操作猛如虎,完成了方案2,可是当时遇到一个问题(导出的内存图无法包括仓库)无法绕过,最近才找到解决方案。该方案特点是,能够任意时刻去导出内存图,不受测验用例履行成果影响。

Xcode 14.2

以下操作将以MemoryGraphDemo为例讲述

0x2 录制测验用例

1.首要,打开MemoryGraphDemo项目,在MemoryGraphDemoUITests.m中编写内存功能测验代码,如下:

- (void)testPerformanceExample {
    XCUIApplication *app = [[XCUIApplication alloc] init];
    XCTMeasureOptions *options = [[XCTMeasureOptions alloc] init];
    options.invocationOptions = XCTMeasurementInvocationManuallyStart;
    [self measureWithMetrics:@[[[XCTMemoryMetric alloc] initWithApplication:app]] options:options block:^{
        [app launch];
        [self startMeasuring];
        //录制测验用例
    }];
}

2.将光标移动至//录制测验用例下方,然后点击Xcode的录制按钮

iOS 内存优化之自动导出内存图

3.等待模拟器启动后,进行开端对页面进行交互。在模拟器中,每做一次UI交互(点击、滑动)Xcode都会在//录制测验用例下方光标位置刺进相应的操作代码。

4.点击模拟器中按钮:Click Me -> Retain Cycles -> Indirect Retain Cycles -> Dynamic Indirect Retain Cycles -> Large Buffers。终究再次点击录制按钮中止录制,终究成果如下图

iOS 内存优化之自动导出内存图

0x3 xcodebuild test

1.履行该测验用例,点击办法前面的履行按钮,如图

iOS 内存优化之自动导出内存图

2.第一次履行测验用例完成后是测验经过的状态,此刻需要为其设置内存值的baseline。

iOS 内存优化之自动导出内存图

3.在本例中将baseline设置为32000kB。

iOS 内存优化之自动导出内存图

4.因为Max STDDEV:10%,所以Average的值在32000kB *(100% – 10%)到32000kB *(100% + 10%)之间测验用例才会履行成功。重新履行测验用例,成果如图,从图中能够看到Xcode中履行时能够读取到过程7中设置的baseline的值。

iOS 内存优化之自动导出内存图

5.xcodebuild test 参数 -enablePerformanceTestsDiagnostics YES来自Detect and diagnose memory issues中的介绍,依照视频中演示,运用了该参数后,当测验用例履行失利,会在xcresult中给出内存图的导出途径。

iOS 内存优化之自动导出内存图
iOS 内存优化之自动导出内存图

6.运用xcodebuild test -workspace MemoryGraphDemo.xcworkspace -scheme MemoryGraphDemo -destination platform="iOS Simulator",name="iPhone 14" -enablePerformanceTestsDiagnostics YES指令履行测验用例,成果如下图

iOS 内存优化之自动导出内存图

在指令的履行成果里,测验用例是履行成功的,原因是xcodebuild运转的测验用例没有读取到baseline,所以无法触发失利流程,导出内存图。

这儿查到些相关案例:

  • setting-baselines-for-performance-tests-using-xcodebuild-and-measure
  • Is it possible to record baseline for Performance tests with xcodebuild?

并且查找xcodebuild相关运用教程,也没有找到设置baseline相关的参数,再对比Detect and diagnose memory issues运用的xcodebuild指令,猜想是xcodebuild存在bug。

0x4 xcodebuild test + expect + lldb

本方案的原理:在xcodebuild履行测验用例期间,经过lldb进行吸附项目进程,并在用例完毕的函数上增加完毕断点,然后在该断点中增加leaks指令,当用例将要履行时,会触发断点,进而调用leaks指令导出*.memgraph内存。

1.新加一个测验用例,详细代码如下

- (void)testLLDBExample {
    XCUIApplication *app = [[XCUIApplication alloc] init];
    app.launchEnvironment = @{@"MallocStackLogging": @"YES"};
    [app launch];
    [app.staticTexts[@"Click Me"] tap];
    XCUIElementQuery *tablesQuery = app.tables;
    [tablesQuery.staticTexts[@"Large Buffers"] tap];
    [tablesQuery.staticTexts[@"Retain Cycles"] tap];
    [tablesQuery.staticTexts[@"Indirect Retain Cycles"] tap];
    [tablesQuery.staticTexts[@"Dynamic Indirect Retain Cycles"] tap];
    //以这个点击操作对应的办法作为触发leaks指令的入口
    [app.tables.staticTexts[@"LLDB Export Memory Graph File"] tap];  
}

这儿以UITest触发点击LLDB Export Memory Graph File这个cell时,作为触发导出内存图的条件。在实在事务场景中,能够以退出登陆的点击事情来作为一次内存回归的内存图导出节点,这样能够便利的观察到非登陆状态下,各个事务对象是否开释洁净。

app.launchEnvironment = @{@"MallocStackLogging": @"YES"};这句启动环境的装备能够使导出的内存图包括仓库。

2.cd /path/to/Scripts切换控制台工作途径到Scripts文件夹下

iOS 内存优化之自动导出内存图

3.给两个脚本履行权限sudo chmod +x emg.sh uitest.sh

4.根据项目修正脚本uitest.sh中的装备

EXECUTE_NAME="MemoryGraphDemo"
SCHEME="MemoryGraphDemoUITests"
ROOT_PATH="../"
TRIGER_CMD="trigerLLDBExportMemoryGraphFile"
OUT_PUT="./"
  • EXECUTE_NAME: 项目进程名
  • SCHEME: xcodebuild test -scheme 的参数
  • ROOT_PATH: 项目根途径(.xcodeproj所在途径)
  • TRIGER_CMD: 触发leaks指令的函数(项目中存在+UITest终究的点击事情)
  • OUT_PUT: 内存图的输出途径

3.履行脚本./uitest.sh

iOS 内存优化之自动导出内存图

MemoryGraphDemo的默认装备,终究会把内存图输出的Scripts途径下

iOS 内存优化之自动导出内存图

0x5 总结

本文介绍了两种主动导出内存图的办法,第一种办法目前存在问题,无法成功触发导出操作,可能是我运用姿态不对(缺少必要的参数装备)或许xcodebuild存在bug,功能正常的情况下,这种办法运用简单,仅在测验用例失利时才导出内存图进行剖析,能够做到按需剖析。第二种办法是利用expect指令给lldb吸附的进程发送交互式指令,完成主动调用leaks导出内存图的办法,该办法灵活性高,不仅仅可运用在这种场景。可是这种办法需要额定分配精力去剖析每次回归的内存图,而第一种办法仅需重视测验用例失利的场景。

所以,对于刚开端重视内存问题的项目,运用第二种办法不断排查和修复相关问题,当项目中的内存问题趋于稳定时, 运用第一种办法来确保项目在迭代时的回归功率和避免再次劣化。

敞开成长之旅!这是我参与「日新方案 2 月更文挑战」的第 1 天,点击检查活动详情