如何全面监控线上iOS千奇百怪的崩溃

App上线后,我们最怕出现的情况就是崩溃了,但是线下我们测试好好的App,为什么上线后就发生崩溃了呢?这些崩溃日志信息是怎么采集的?能够采集的全吗?采集后又要怎么分析,解决呢?

App上线后,是很脆弱的,导致其崩溃的问题,不仅包括编写代码时的各种马虎,还包括那些被系统强杀的疑难杂症.下面我们先看常见的几个编写代码时的小马虎,是如何让应用崩溃的.
1.数组越界:在取数据索引时越界,App会发生崩溃,还有一种情况,就是给数据添加一个nil元素会崩溃
2.多线程问题:在子线程中进行UI更新可能会发生崩溃,多个线程进行数据的读取操作,因为处理时机不一致,比如有一个线程在置空数据的同时另一个线程在读取这个数据,可能会出现崩溃情况
3.主线程为响应:如果主线程超过系统规定的时间无响应,会被Watchdog杀掉,这时,崩溃问题对应的异常编码是0x8badf00d.
4.野指针:指针指向一个已删除的对象访问内存区域时,会出现野指针崩溃,野指针问题是需要我们重点关注的,因为它是导致App崩溃的最常见,也是最难定位的一种情况,

一般崩溃都是由崩溃监控系统收集的,收集的是堆栈信息,这些堆栈信息也是解决崩溃问题的重要依据

崩溃信息的收集并没有那么简单,因为,有的崩溃日志是可以通过信号捕捉到的,而很多崩溃日志是通过信号捕捉不到的,下图可视


Snip20190413_1.png

从这张图片中可以看出KVO问题,通知线程问题,数据越界,野指针等崩溃信息,可以通过信号捕捉,但是,像后台任务超时,内存被打爆,主线程卡顿超阈值等信息,是无法通过信号捕捉到的,接下来我们就看两种不同的崩溃情况怎么捕捉

信号可捕捉的崩溃日志收集

收集崩溃日志最简单的方法就是打开Xcode的菜单选择Product -> Archive.然后在提交时选上"Upload your app`s symbols to receive symbolicated reports from Apple",以后你就可以直接在Xcode的Archive里看到符号化的崩溃日志了.
这种查看日志的方式,每次都是纯手工操作,时效性较差,目前很多公司的崩溃日志监控系统,都是通过PLCarshReporter这样的三方开源库捕捉崩溃日志的,然后上传到自己服务器上进行整体监控,而没有服务端开发能力或者对数据不敏感的公司,这会使用Bugly这样的三方提供的完整的监控捕捉崩溃SDK进行集成统计.

那么为什么PLCrashReporter和Bugly这类工具,是怎么知道App是什么时候崩溃呢?

在崩溃日志里,我们会经常看到下面这段说明

Type:  EXC_BAD_ACCESS (SIGSEGV)

它表示的事,EXC_BAD_ACCESS这个异常会通过SIGSEGV信号发现有问题的线程,虽然信号的种类有很多,但是都可以通过注册signalHandler来捕捉,起实现代码如下

void registerSignalHandler(void){
    signal(SIGSEGV, handleSignalException);//试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
    signal(SIGFPE, handleSignalException);//在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。
    signal(SIGBUS, handleSignalException);//非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。
    signal(SIGPIPE, handleSignalException);//管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止
    signal(SIGHUP, handleSignalException);//本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个 Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进 程组和后台有终端输出的进程就会中止。不过可以捕获这个信号,比如wget能捕获SIGHUP信号,并忽略它,这样就算退出了Linux登录, wget也 能继续下载。此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
    signal(SIGINT, handleSignalException);//程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进  程组终止进程。
    signal(SIGQUIT, handleSignalException);//和SIGINT类似, 但由QUIT字符(通常是Ctrl-)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。
    signal(SIGABRT, handleSignalException);//调用abort函数生成的信号。
    signal(SIGILL, handleSignalException);//执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号。
}
void handleSignalException(int signal){
    NSMutableString * crashString = [[NSMutableString alloc]init];
    void * callStack[128];
    int i, frames = backtrace(callStack,128);
    char ** traceChar = backtrace_symbols(callStack,frames);
    for (i = 0; i < frames; ++i) {
        [crashString appendString:@"%s\n",traceChar[i]];
    }
    NSLog(crashString);
}

上面这段代码会各种信号都进行了注册,捕捉到异常信号后,在处理方法handleSignalException里通过backtrace_symbols方法可以获取到当前的堆栈信息,堆栈信息先保存到本地,下次启动时在上传到奔溃监控服务器就可以了

信号不可捕捉的崩溃日志收集

我们可能会遇到App退到后台后,即使代码逻辑没有问题也容易出现崩溃,而且这些崩溃往往是因为系统强杀掉了某些进程导致的,而系统强杀抛出的信号还由于系统限制无法被捕捉到.

那么,后台容易崩溃的原因是什么呢?如何避免后台崩溃?怎么去收集后台信号捕捉不到的那些崩溃信息呢?还有那些信号捕捉不到的崩溃情况?怎么去监控其他无法通过信号捕捉的崩溃信息?

下面我们就带着这五个问题来了解信号不可捕捉的崩溃

后台容易崩溃的原因是什么?

首先我们知道iOS后台包活的5种方式:Background Mode,Background Fetch,Silent Push,PushKit,Background Task
1.使用Background Mode方式的话,AppStore在审核时会提高对App的要求,通常情况下,只有那些地图,音乐播放,VoIP类的App才能通过审核
2.Background Fetch 方式的唤醒时间不稳定,而且用户可以在系统设置关闭这种方式,导致他的使用场景很少
3.Silent Push是推送的一种,会在后台唤起App 30秒.会调起application:didReceiveRemoteNotifiacation这个delegate和普通的remote pushnotification推送调用的delegate是一样的
4.PushKit后台唤醒App后能够包活30秒,他主要用于提升VoIp应用的体验
5.Background Task方式,是使用最多的,App退到后台后,默认都会使用这种方式

接下来看一下使用最多的Background Task方式:
在程序退到后台后,只有几秒钟的时间可以执行代码,接下来会被系统挂起,进程挂起后所有的线程都会暂停,不管这个线程是文件读写还是内存读写都会被暂停,但是,数据读写过程无法暂停只能被中断,中断时数据读写异常而且容易损坏文件,所以系统会选择主动杀掉进程.

Background Task就是系统提供了baginBackgroundTaskWithExpirationHandler方法来延长后台执行时间,可以解决退到后台还需要一些时间去处理一些任务的诉求.

Background Task方式的使用方法,如下代码

- (void)applicationDidEnterBackground:(UIApplication *)application {
    self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
        [self youTask];
    }];
}

这段代码中,youTask任务最多执行3分钟,3分钟内youTask运行完成,你的App就会挂起,如果youTask在三分钟内没有执行完的话,就会被系统强行杀掉进程,造成崩溃.

如何避免后台崩溃呢?

如果我们想要避免这种崩溃发生的话,就需要严格控制后台数据的读写操作,比如,可以先判断需要处理的数据大小,如果数据过大,也就是在后台限制时间内或延长后台执行时间后也处理不完的话,可以考虑在程序下次启动或后台唤醒时在进行处理

怎么去收集后台信号捕捉不到的那些崩溃信息呢?

采用Background Task方式时,我们可以根据beginBackgroundTaskWithExpirationHandler会让后台包活三分钟,先设置一个定时器,在接近三分钟的时候判断后台程序是否还在执行,如果还在执行的话,我们就可以判断该程序即将后台崩溃,进行上报记录,已达到监控的效果

还有那些信号捕捉不到的崩溃情况?怎么去监控其他无法通过信号捕捉的崩溃信息?

其他捕捉不到的崩溃情况还有很多,主要就是内存打爆和主线程卡顿时间超过阈值被watchdog杀掉,其实监控这两种崩溃的思路和监控后台崩溃类似,我们要先找到他们的阈值,然后在临近阈值时还在执行的后台程序,判断为将要崩溃,收集信息并上报

注:以上文章为学习戴铭(iOS开发课程)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,107评论 1 32
  • 写在前面:本文会在最开头将苹果官方的文档Understanding and Analyzing Applicati...
    小小外星人阅读 25,989评论 23 130
  • “跟你在一起,浪费我的时间。”这大概是很多人都听过的一句话。 现在的人,都讲究效率,恋爱也变得有效率起来,不以结婚...
    慕容匪我阅读 2,144评论 22 29
  • 地下车库,车子停稳的刹那 雨生还在唱,一天到晚游泳的鱼呀,鱼 双腿无法动弹,暮色散落四方 泪水落到水中,是否就不咸...
    蒋菱阅读 383评论 0 0
  • 前几天晚上突然牙痛,痛到眼泪都出来了,由于是半夜,只能第二天再去看牙医。到了牙科,医生说我的牙坏到了神经,要治疗再...
    淡眠阅读 298评论 0 0