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的录制按钮
3.等待模拟器启动后,进行开端对页面进行交互。在模拟器中,每做一次UI交互(点击、滑动)Xcode都会在//录制测验用例
下方光标位置刺进相应的操作代码。
4.点击模拟器中按钮:Click Me
-> Retain Cycles
-> Indirect Retain Cycles
-> Dynamic Indirect Retain Cycles
-> Large Buffers
。终究再次点击录制按钮
中止录制,终究成果如下图
0x3 xcodebuild test
1.履行该测验用例,点击办法前面的履行按钮,如图
2.第一次履行测验用例完成后是测验经过的状态,此刻需要为其设置内存值的baseline。
3.在本例中将baseline设置为32000kB。
4.因为Max STDDEV:10%
,所以Average的值在32000kB *(100% – 10%)到32000kB *(100% + 10%)之间测验用例才会履行成功。重新履行测验用例,成果如图,从图中能够看到Xcode中履行时能够读取到过程7中设置的baseline的值。
5.xcodebuild test 参数 -enablePerformanceTestsDiagnostics YES
来自Detect and diagnose memory issues中的介绍,依照视频中演示,运用了该参数后,当测验用例履行失利,会在xcresult中给出内存图的导出途径。
6.运用xcodebuild test -workspace MemoryGraphDemo.xcworkspace -scheme MemoryGraphDemo -destination platform="iOS Simulator",name="iPhone 14" -enablePerformanceTestsDiagnostics YES
指令履行测验用例,成果如下图
在指令的履行成果里,测验用例是履行成功的,原因是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文件夹下
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
按MemoryGraphDemo
的默认装备,终究会把内存图输出的Scripts途径下
0x5 总结
本文介绍了两种主动导出内存图的办法,第一种办法目前存在问题,无法成功触发导出操作,可能是我运用姿态不对(缺少必要的参数装备)或许xcodebuild存在bug,功能正常的情况下,这种办法运用简单,仅在测验用例失利时才导出内存图进行剖析,能够做到按需剖析。第二种办法是利用expect指令给lldb吸附的进程发送交互式指令,完成主动调用leaks导出内存图的办法,该办法灵活性高,不仅仅可运用在这种场景。可是这种办法需要额定分配精力去剖析每次回归的内存图,而第一种办法仅需重视测验用例失利的场景。
所以,对于刚开端重视内存问题的项目,运用第二种办法不断排查和修复相关问题,当项目中的内存问题趋于稳定时, 运用第一种办法来确保项目在迭代时的回归功率和避免再次劣化。
敞开成长之旅!这是我参与「日新方案 2 月更文挑战」的第 1 天,点击检查活动详情