前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS Abort 问题系统的解决方案

iOS Abort 问题系统的解决方案

原创
作者头像
ios-lan
修改2020-09-17 14:31:42
2K0
修改2020-09-17 14:31:42
举报
文章被收录于专栏:ios技术安装ios技术安装

一、背景

崩溃(Crash),即闪退,多指移动设备(如iOS、Android设备)在打开/使用应用程序的过程中,突然出现意外退出/中断的情况。如果App线上版本频繁发生崩溃,会极大地影响用户体验,甚至导致用户流失,以及收益减少。因此,崩溃问题是客户端稳定性团队需要重点解决的问题。

茫茫人海中,你看到这一段文字,浪费你三秒钟的时间,欢迎你来一场iOS交流技术的碰撞,互相学习,共同提高技术![563513413](https://jq.qq.com/?_wv=1027&k=lzJejkSl)

然而,对于所有崩溃场景,仅25%的崩溃可通过信号量捕获,实施相应改进;另有75%的崩溃则难以识别,从而对App的用户体验,造成了巨大的潜在影响。

Facebook的工程师将App退出分为以下6个类别:

1.App内部主动调用exit()或abort()退出;

2.App升级过程中,用户进程被杀死;

3.系统升级过程中,用户进程被杀死;

4.App在后台被杀死;

5.App在前台被杀死,且可获取堆栈;

6.App在前台被杀死,且无法获取堆栈。

对于第1~4类退出,属于App的正常退出,对用户体验没有太大影响,无需进行相应处理;对于第5类退出,可通过堆栈代码级定位崩溃原因,对此业界已形成比较成熟的解决方案,;对于第6类退出,可能的原因很多,包括但不限于:系统内存不足时继续申请内存、主线程卡死20s以上、CPU使用率过高Stack Overflow等,在此我们统一称之为iOS客户端的“Abort问题”。

Abort问题无法被堆栈捕获,且发生频次远高于可被捕获的崩溃(下称“堆栈崩溃”)。从历史数据来看,手淘(电商类超级App代表)的Abort问题数量一般是堆栈崩溃数量的3倍左右;优酷Pad(视频类超级App代表)的Abort问题数量一般是堆栈崩溃数量的5倍左右。可见,Abort问题对用户的使用体验造成巨大影响。

本文将针对iOS客户端的Abort问题,进行根因定位分析,并提出系统性解决方案。

二、Abort问题的原因分类

形成Abort问题的原因主要包括以下4个。

2.1 内存Jetsam

移动端设备的物理内存资源紧张,但App仍不断申请内存。因此系统signal 9杀死进程,造成异常退出。

代码语言:javascript
复制
{   "memoryPages" : {     "active" : 24493,     "throttled" : 0,     "fileBacked" : 24113,     "wired" : 13007,     "anonymous" : 12915,     "purgeable" : 127,     "inactive" : 10955,     "free" : 2290,     "speculative" : 1580  },  "uncompressed" : 125795,  "decompressions" : 143684  },  "largestProcess" : "Taobao4iPhone",  "processes" : [  {  ...  {     "rpages" : 2050,     "states" : [       "frontmost",       "resume"     ],     "name" : "Taobao4iPhone",     "pid" : 1518,     "reason" : "vm-thrashing",     "fds" : 50,     "uuid" : "5103a88a-917f-319e-8553-c0189dd1abac",     "purgeable" : 127,     "cpuTime" : 4.619693,     "lifetimeMax" : 3557  },  ...  }

2.2 主线程死锁

A/B两个线程同时等待对方完成某些操作,因而无法继续执行,形成死锁,造成异常退出。

代码语言:javascript
复制
Exception Type:  00000020Exception Codes: 0x000000008badf00dHighlighted Thread:  0 Application Specific Information:com.myapp.myapp failed to scene-create in time Elapsed total CPU time (seconds): 4.230 (user 4.230, system 0.000), 10% CPU Elapsed application CPU time (seconds): 1.039, 3% CPU Thread 0 name:  Dispatch queue: com.apple.main-threadThread 0:0   libsystem_kernel.dylib          0x36360540 semaphore_wait_trap + 81   libdispatch.dylib               0x36297eee _dispatch_semaphore_wait_slow + 1862   libxpc.dylib                    0x364077b8 xpc_connection_send_message_with_reply_sync + 1523   Security                        0x2b8dd310 securityd_message_with_reply_sync + 644   Security                        0x2b8dd48c securityd_send_sync_and_do + 445   Security                        0x2b8ea452 __SecItemCopyMatching_block_invoke + 1666   Security                        0x2b8e96f6 SecOSStatusWith + 147   Security                        0x2b8ea36e SecItemCopyMatching + 174

2.3 启动/重启超时

App由于启动/重启的时间超过系统允许的时间限制,造成异常退出。

代码语言:javascript
复制
scene-create watchdog transgression: app exhausted real (wall clock) time allowance of 19.93 seconds, Elapsed total CPU time (seconds): 21.050 (user 21.050, system 0.000)

2.4 CPU打爆

主线程死锁、启动/重启超时,都可能间接导致CPU打爆,造成异常退出。

三、Abort问题的根因定位

Abort问题常常没有明显线索进行问题定位,因此,解决难度比较大。手淘曾经历过很多次Abort问题数量飙升,但无从下手的事故,甚至还有一两次发生在双11前不久,但往往以“一群人苦逼的众测复现、复现之后也无法确定是否真的复现”收场。

因此,我们迫切需要基于已有经验,形成一套完整的解决方案,快速、准确地定位/解决问题。这就需要我们从以下几个方面着手进行考虑:

1.Abort问题发生的场景:例如,哪个页面、什么操作。

2.Abort问题发生的原因:例如,内存Jetsam、主线程死锁、启动/重启超时、CPU打爆。

3.对于内存Jetsam,需进一步定位到是否发生了内存泄露以及泄露的循环引用(Retain Cycle)。

4.对于主线程死锁,需进一步定位到卡死的堆栈。

5.对于启动/重启超时,以及CPU打爆,需进一步定位到堆栈。

接下来,我们以手淘的主线程死锁问题为例,进行根因分析。首先,来看一下某版本手淘Abort问题数据的总体视图:

由于Abort问题出现之前,内存、CPU使用量正常,因此初步判断造成异常退出的原因为主线程死锁。

查看相关日志文件,验证时间、线索吻合,因此可最终确定造成异常退出的原因为主线程死锁。

四、Abort问题的系统性解决方案

4.1 Abort系统性解决方案难点:现场捕获

为实现Abort问题的系统性解决方案,需充分考虑以下问题:

1.通过signal 9杀死进程造成的Abort问题,往往难以通过信号量捕获至堆栈。在这种情况下,应如何尽可能完整地捕获崩溃现场的关键信息?具体包含哪些信息?

2.App崩溃时系统处于极不稳定的状态,应如何保证崩溃现数据稳定落盘?

3.在信息采集、数据捕获的过程中,需对大量数据进行写入操作,应如何保证日志高性能写入?

4.在数据量较大的情况下,数据的存储、上传可能对系统造成较大压力,应如何保证数据的高压缩率?

基于以上考虑,我们提出并设计了一套基于mmap的高性能、高压缩率、高一致性、可自解释的trace文件协议,作为iOS端高可用体系的数据载体。

4.1.1 mmap数据存储层保证数据写入的高性能和高一致性

1.通过mmap将一个文件或者其它对象映射到进程的地址空间,对内存的操作会由内核将数据写到对应的磁盘文件上;数据写入的性能与内存操作相当(略比内存操作高)

2.用户进程崩溃之后,这块映射区仍由内核管理,可以保证数据的一致性

4.1.2 二进制编码协议保证数据压缩率最高

1.具体编码协议

2.实测编码在压缩率能达到80%以上,或者直观一点说,使用50k的内存可以记录下用户二十分钟内详细的使用记录,包括页面访问记录、系统事件、秒级别的内存、CPU数据。

4.1.3 尽可能多的记录系统多维度指标及异常事件

包括:

1.性能数据,包括CPU、内存数据,用于判断应用当前是不是处理overload状态

2.大内存申请

3.Retain Cycle,用于定位Jetsam Event

4.卡顿,用于定位watch dog kill

5.当前存活VC实例数量

五、总结

在App的世界里,功能层面的差异已经越来越难以体现。在这种情况下,良好的用户体验,往往是App致胜的关键。而Abort问题对于每一个App而言,都是对用户体验的最大挑战,需要App开发者给予足够的重视。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、Abort问题的原因分类
    • 2.1 内存Jetsam
      • 2.2 主线程死锁
        • 2.3 启动/重启超时
          • 2.4 CPU打爆
          • 三、Abort问题的根因定位
          • 四、Abort问题的系统性解决方案
            • 4.1 Abort系统性解决方案难点:现场捕获
              • 4.1.1 mmap数据存储层保证数据写入的高性能和高一致性
              • 4.1.2 二进制编码协议保证数据压缩率最高
              • 4.1.3 尽可能多的记录系统多维度指标及异常事件
          • 五、总结
          相关产品与服务
          数据保险箱
          数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档