iOS常见崩溃简介

1. 崩溃

多指在移动设备(如iOS、Android设备)中或不可移动设备(如:Windows、Linux等设备),
在打开或使用应用程序时出现的突然退出中断的情况(类似于Windows的应用程序崩溃)。

多表现为:应用程序画面一闪而过,随即退回到桌面。

崩溃会影响用户体验,造成用户流失,因此,我们要重视崩溃
在这里插入图片描述

根据不同场景,崩溃收集方式不同

Xcode编译期间:

在这里插入图片描述

测试机获取:

Xcode->Window->Devices and Simulators
在这里插入图片描述
或者
设置->隐私->分析与改进

线上崩溃采集:

封装好的三方,直接接入的:友盟、bugly、听云
开源的SDK:KSCrash、plcrashreporter

2. 崩溃产生的原因

划分方式一:

  • cpu无法执行的代码
  • 被系统强杀
  • 语言触发异常

2.1 cpu无法执行的代码

  • 无效指令或操作
  • 访问无效地址及不具有权限的内存地址
  • 除以0等
  • 僵尸对象

2.2 被系统强杀

  • 应用内存消耗过高,即OOM问题
  • 主线程长时间无法响应ANR
  • 资源异常
  • 死锁
  • 非法的应用签名
  • 后台执行超时

2.3 语言触发异常

  • OC语言抛出异常
  • C++抛出异常

划分方式二:

除了上面的划分方式,崩溃还可以按:软件异常硬件异常划分

软件异常:
软件异常主要来自 kill(),pthread_kill()。iOS 中的 NSException 未捕获,abort 都属于这种情况。

硬件异常:
硬件的信号始于处理器 trap,是和平台相关的。野指针崩溃大部分是硬件异常。

软件异常的流程是:

软件异常 -> Unix信号

硬件异常的流程是:

硬件异常 -> Mach异常 -> Unix信号
在这里插入图片描述

在这里插入图片描述

Mach 异常:

  • EXC_BAD_ACCESS: 不能访问的内存
  • EXC_BAD_INSTRUCTION: 非法或未定义的指令或操作数
  • EXC_ARITHMETIC: 算术异常(例如除以0)。iOS 默认是不启用的,所以我们一般不会遇到
  • EXC_EMULATION: 执行打算用于支持仿真的指令
  • EXC_SOFTWARE:软件生成的异常,我们在 Crash 日志中一般不会看到这个类型,苹果的日志里会是 EXC_CRASH
  • EXC_BREAKPOINT:跟踪或断点
  • EXC_SYSCALL: UNIX 系统调用
  • EXC_MACH_SYSCALL: Mach 系统调用

UNIX 信号:

  • SIGSEGV,段错误。访问未分配内存、写入没有写权限的内存等。
  • SIGBUS,总线错误。比如内存地址对齐、错误的内存类型访问等。
  • SIGILL,执行了非法指令,一般是可执行文件出现了错误。
  • SIGFPE ,致命的算术运算。比如数值溢出、NaN数值等。
  • SIGABRT,调用 abort() 产生,通过 pthread_kill() 发送。
  • SIGPIPE,管道破裂。通常在进程间通信产生。比如采用FIFO(管道)通信的两个进程,读管道* 没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。根据苹果相关文档,可以忽略这个信号。
  • SIGSYS,系统调用异常。
  • SIGKILL,此信号表示系统中止进程。崩溃报告会包含代表中止原因的编码。exit(), kill(9) 等函数调用。iOS 系统杀进程,如 watchDog 杀进程。
  • SIGTRAP,断点指令或者其他trap指令产生。

当我们拦截信号处理之后是可以让程序不崩溃而继续运行的,但是不建议这样做,因为程序已经处于异常不可知状态。
看上图里面最终都会转换为 “UNIX信号”, 是不是代表我们只用监听 “UNIX 信号” 就够了呢?为什么还要拦截 Mach 异常呢?

不是所有的 "Mach异常” 类型都映射到了 “UNIX信号”
“UNIX信号” 在崩溃线程回调,如果遇到 Stackoverflow 问题,已经没有条件(栈空间)再执行回调代码了。

捕获到异常信号后,在处理方法 handleSignalException 里通过 backtrace_symbols 方法就能获取到当前的堆栈信息。
堆栈信息可以先保存在本地,下次启动时再上传到崩溃监控服务器就可以了。

Mach是一个XNU的微内核核心

在这里插入图片描述

3. 崩溃日志包含信息

基本信息:崩溃发生的日期、iOS 版本等
进程信息:崩溃进程的相关信息,比如崩溃报告唯一标识符、唯一键值、设备标识
异常信息:异常类型、异常编码、异常的线程;
线程回溯:崩溃时的方法调用栈

崩溃日志调用栈内容:
在这里插入图片描述
这样直接看崩溃信息的调用栈,是看不懂的

我们需要一个.DSYM文件,dSYM 是保存 函数地址映射信息的中转文件,其中包含文件名、方法名、行号等信息

在这里插入图片描述
一个ipa包,对应一个.DSYM文件

在这里插入图片描述
通过.DSYM文件的解析,就可以找到对应的文件名和函数名

4. 开发中常见崩溃

  • unrecognized selector crash
  • KVO crash
  • NSNotification crash
  • NSTimer crash
  • Container crash(数组越界,插nil等)
  • NSString crash (字符串操作的crash)
  • UI not on Main Thread Crash (非主线程刷UI(机制待改善))

unrecognized selector crash

当一个对象找不到对应的方法实现的时候,会报此类错误

在找不到方法时,查找方法将会进入方法forward流程,系统给了三次补救的机会,
所以我们要解决这个问题,在这三次均可以解决这个问题
在这里插入图片描述

KVO crash

KVO监听对象属性值的改变

KVO 日常使用造成崩溃的原因通常有以下几个:

  • KVO 添加次数和移除次数不匹配:
  • 移除了未注册的观察者,导致崩溃。
  • 重复移除多次,移除次数多于添加次数,导致崩溃。
  • 重复添加多次,虽然不会崩溃,但是发生改变时,也同时会被观察多次。
  • 被观察者提前被释放,被观察者在 dealloc 时仍然注册着 KVO,导致崩溃。

NSNotification crash

当一个对象添加了notification之后,如果dealloc的时候,仍然持有notification,就会出现NSNotification类型的crash。

在iOS9以及iOS9以后,可以不做移除通知操作

NSTimer crash

一般是在定时器被target强引用没有被释放,产生内存泄露,或者在定时器触发的时候导致崩溃
解决方案:
1.NSTimer使用Block,对其target不强引用
2.是否找到一个合适的时机,在确定NSTimer已经失效的情况下,让NSTimer自动invalidate
3.使用中间变量

类族(NSArray,NSMutableArray,NSDictonary,NSMutableDictionary)

  • 插入空对象
  • 数组越界
  • 不可变类型插入数据

建议:

  • 加三目运算符,防止数据为空
  • 数组取值的时候,判断数组个数
  • 遇到可变类型,使用strong修饰

非主线程刷UI

UI刷新,必须在主线程操作
在子线程中,需要刷新UI的时候,要切换到主线程

野指针

在这里插入图片描述

定义:当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称野指针

若操作系统将这部分已经释放的内存重新分配给另外一个进程,而原来的程序重新引用现在的迷途指针,则将产生无法预料的后果。因为此时迷途指针所指向的内存现在包含的已经完全是不同的数据。

在这里插入图片描述

解决方法:

Xcode开启僵尸对象监听
在这里插入图片描述

使用MLeaksFinder或其他三方库,排查内存泄露问题
在这里插入图片描述

使用JJException,减少App闪退
当然,最好做到:开发过程不使用,正式包开启
在这里插入图片描述


参考资料:
iOS 野指针处理
iOS野指针定位总结


Chat-GPT有关野指针的解释

问:iOS野指针错误一般由什么引起的?怎么排查与避免?

答:

iOS 开发中的野指针错误通常是指向一个已经被释放的对象的指针仍然被访问时发生的错误。这种错误可能导致应用崩溃或不稳定的行为。野指针错误的主要原因包括但不限于:

  1. 对象被提前释放:当你尝试访问一个已经被释放的对象时,就会出现野指针错误。这通常是因为对象的引用计数被错误管理,如被提前释放或没有正确地持有对象。
  2. 内存管理不当:在手动管理内存(如使用MRC, 手动引用计数)的项目中,如果没有正确地平衡retain和release调用,可能会导致对象提前释放,从而引发野指针错误。
  3. 指针未初始化或重置:使用未初始化的指针或者在释放对象后未将指针设为nil,也可能导致野指针访问。

如何排查野指针错误:

  1. 使用Xcode的调试工具:利用Xcode的调试工具,如LLDB调试器,可以帮助你定位野指针的来源。Zombies工具尤其有用,它可以帮助追踪已释放对象的访问尝试。
  2. 代码审查:定期进行代码审查可以帮助发现潜在的内存管理错误,特别是对于使用MRC的项目。
  3. 静态分析工具:Xcode自带的静态分析工具可以帮助检测潜在的内存管理问题,包括可能导致野指针错误的情况。

如何避免野指针错误:

  1. 使用自动引用计数(ARC):自动引用计数可以大大减少内存管理错误。确保项目启用ARC,让编译器帮助管理对象的生命周期。
  2. 指针置nil:在释放对象后,将指向该对象的指针置为nil,这样即使尝试访问该指针,也不会导致崩溃。
  3. 避免使用未初始化的指针:在声明指针变量时,初始化为nil,以避免使用未初始化的指针。
  4. 遵循内存管理规则:即使在ARC环境下,也需要理解并遵循基本的内存管理规则,如不要持有非自己创建的对象,除非这个对象已经明确地被retain了。
  5. 使用弱引用:对于不需要拥有对象的引用,使用弱引用可以避免循环引用和提前释放的问题。

通过采取这些措施,你可以显著减少应用中野指针错误的发生,提高应用的稳定性和可靠性。

不得不说,回答的还蛮好的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2871612.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

关于IP-Adapter的十几个模型,到底是干啥用的?

🎠背景介绍 IP-Adapter的一系列模型在stable diffusion的实际应用中,越来越被频繁的使用到,用于“换脸”或者“保证角色的一致性”,但是很多朋友在安装或者使用别人的工作流的时候,经常会遇到各种各样的问题&#xff…

考研数二要掌握的初中知识点

文章目录 一、整式1. 同底数幂的乘法2. 幂的乘方3. 积的乘方4. 乘法分配律5. 同底数幂的除法 二、分式1. 分式的乘法2. 分式的除法3. 分式的乘方4. 分式的最简公分母5. 负指数幂6. 比例变形7. 分离常数法 三、二次根式0. 平方根和算数平方根的重要概念1. 乘方去根号2. 二次根式…

118. 杨辉三角(Java)

这里写目录标题 题目描述:输入:输出:代码实现: 题目描述: 给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 输入: numRows 5输出: [[1],[1,1],[1…

考研数学|武忠祥各阶段搭配用书汇总

看到有人问武忠祥老师,不请自来 武忠祥老师,绝对的宝藏老师,我在考研强化阶段的时候听过他的强化课程,听完之后,很多问题都想通了,所以,如果有人想问武忠祥老师行不行,那我就一个字…

19. UE5 RPG使用GameplayEffect的Attribute Based Modifiers

前几篇文章我也说了GE的基础使用,但是,对一些属性的应用没有述说,后续,我将一点一点的将它们如何使用书写下来。 这一篇,主要就讲解一下Attribute Based Modifiers使用,先说一下它的应用场景,一…

数据结构——栈和队列的表示与实现详解

目录 1.栈的定义与特点 2.队列的定义与特点 3.案例引入 4.栈的表示和操作的实现 1.顺序栈的表示 代码示例: 2.顺序栈的初始化 代码示例: 3.判断栈是否为空 代码示例: 4.求顺序栈长度 代码示例: 5.清空顺序栈 …

Spring Boot中application配置文件的生效顺序

Spring Boot的一个重要特性就是它的自动配置,这一特性在很大程度上依赖于名称为application的配置文件。本文将详细介绍在Spring Boot中,这些配置文件的加载顺序以及每份文件的应用范围。 文章目录 配置文件的种类配置文件的加载顺序配置文件的环境切换 …

操作系统内功篇:硬件结构之CPU缓存一致性

一 CPU Cache的数据写入 1.1 CPU Cache的结构 是由很多个Cache Line组成的,CPU Line是CPU从内存读取的基本单位,CPU Line是由多个标志数据块组成。 1.2 CPU Cache数据的写入 数据不仅仅只有读取,还有数据的写入,写入数据也是先…

【智能算法】斑鬣狗优化算法(SHO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过。 3.代码实现4.参考文献 1.背景 2017年,Dhiman等人受到斑鬣狗自然狩猎行为启发,提出了斑鬣狗优化算法(Spotted Hyena Optimizer, SHO)。 2.算法原理 2.1算法思想 SHO将斑鬣狗狩猎行为分为围捕-狩猎-进攻三…

JVM实战篇

内存调优 内存溢出和内存泄漏 内存泄漏:在java中如果不再使用一个对象,但是该对象依然在GC ROOT的引用链上,这个对象就不会被垃圾回收器回收。 内存泄漏绝大多数情况都是由堆内存泄漏引起的,所以后续没有特别说明则讨论的都是堆…

matplotlib画堆叠、并列直方图

在用 matplotlib.pyplot.hist 画分布图时,若总分布由几个分量组成(如高斯混合),想用不同颜色标识出来,方便看到各分量占比,参考 [1]。 效果: 分布由两个分量(x、y)组成…

二,几何相交---4,BO算法---(4)可能的三种情况

从上到下,扫描线经过有三种情况: 第一种情况,加入线段e的左端点,那么原来的状态pred->suc变成pred->e->suc 第二种情况,经过线段e的右端点,状态pred->e->suc,变成pred->suc&a…

Java 面试题之框架

1. Spring 是什么 Sping 是包含了众多工具方法的 IOC 容器,IOC是控制反转,说的是对象的创建和销毁的权利都交给 Spring 来管理了, 它本身又具备了存储对象和获取对象的能力. 。 容器:字面意思,用来容纳某种物品的装置。 比如 L…

JavaScript练手小技巧:数字反转时钟

样式基于博主的这篇文章: CSS3技巧38:3D 翻转数字效果-CSDN博客 既然可以实现翻转数字了,肯定就可以跟 JS 相结合去完成一些数字展示效果。 比如,数字反转时钟。 为了方便,所有 HTML 数字根据时间动态生成。因此&a…

企业内部培训考试系统培训计划功能说明

培训计划是预设好的一套课程系列,包含课程和考试,分多个阶段,每完成一个阶段就会在学习地图上留下标记,让用户看到自己的努力成果,增强成就感,从而坚持完成课程。 企业内部培训考试系统中如何设置培训计划…

一起玩儿3D打印机——06 Marlin固件的配置(三)

摘要:本文介绍Marlin固件的配置方法 25. 启用EEPROM参数保存功能 #define EEPROM_SETTINGS 打开此功能,会将部分参数保存在打印机中,这样通过屏幕就可以进行调节,而无需重刷固件。 26. 启用板载SD卡支持 #define SDSUPPORT 如…

【QT+QGIS跨平台编译】之七十七:【QGIS_Gui跨平台编译】—【错误处理:字符串错误】

文章目录 一、字符串错误二、处理方法三、涉及到的文件一、字符串错误 常量中有换行符错误:(也有const char * 到 LPCWSTR 转换的错误) 二、处理方法 需要把对应的文档用记事本打开,另存为 “带有BOM的UTF-8” 三、涉及到的文件 src\gui\qgsadvanceddigitizingdockwidge…

WebServer -- 架构图 面试题(上)

目录 🎂前言 🌼流程图 && 架构图 1)什么是 WebServer 2)服务器基本框架 3)Reactor && Proactor 模式 4)同步 I/O 模拟Proactor模式(Linux) 5)主从…

C语言基础练习——Day10

目录 选择题 编程题 不用加减乘除做加法 找到所有数组中消失的数字 选择题 1、求函数返回值,传入-1,则在64位机器上函数返回 int func(int x) {int count 0;while (x){count;x x&(x - 1);//与运算}return count; } A 死循环B 64C 32D 16 答案&…

别急,先了解一下什么是REST API吧

1、先想一想Rest API的用途和场景 Rest API的常用场景:前后端分离,前端可多样化,还有与其他系统集成:RESTful API 可以与其他系统进行集成,例如第三方登录、支付和社交媒体平台等。 现在我们知道了如何使用 servlet …