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://www.rhkb.cn/news/280260.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024.3.21 如何将idea的注释设置为在首字母前开始而不是句首

2024.3.21 如何将idea的注释设置为在首字母前开始而不是句首 两种写法的差异 修改办法 将右下角的勾去掉即可。

[ROS 系列学习教程] rosbag Python API

ROS 系列学习教程(总目录) 本文目录 1. 构造函数与关闭文件2. 属性值3. 写bag文件内容4. 读bag文件内容5. 将bag文件缓存写入磁盘6. 重建 bag 文件索引7. 获取bag文件的压缩信息8. 获取bag文件的消息数量9. 获取bag文件记录的起止时间10. 获取话题信息与消息类型 rosbag 的 Pyt…

【Leetcode-73.矩阵置零】

题目: 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1: 输入:matrix [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]]示例 2&…

echart trigger 为 axis 的时候不显示 tooltip 解决办法

echart trigger 为 axis 的时候不显示 tooltip 解决办法 在项目 vitetsvue3 中使用 echart 显示了一个曲线图: 但当把图表的 trigger 设置成 axis 的时候,鼠标扫过并不显示具体的数值,如上图所示。 但 trigger item 的时候是正常的。 解决…

在DevEco Studio中第一次使用网络图片不显示问题

当我们新建项目 第一次使用网络图片 没有显示时 加这段代码就可以了 如果刷新图片还是没有显示 就重启编辑器。 "requestPermissions": [{"name": "ohos.permission.INTERNET"}],

如何构建Docker自定义镜像

说明:平常我们使用Docker运行各种容器,极大地方便了我们对开发应用的使用,如MySQL、Redis,以及各种中间件,使用时只要拉镜像,运行容器即可。本文介绍如何创建一个Demo,自定义构建一个镜像。 开…

31.HarmonyOS App(JAVA)鸿蒙系统app Service服务的用法

鸿蒙系统app Service服务的用法 后台任务调度和管控 HarmonyOS将应用的资源使用生命周期划分为前台、后台和挂起三个阶段。前台运行不受资源调度的约束,后台会根据应用业务的具体任务情况进行资源使用管理,在挂起状态时,会对应用的资源使用进…

【研发日记】,Matlab/Simulink开箱报告(十)——Requirements Toolbox

前言 见《开箱报告,Simulink Toolbox库模块使用指南(五)——S-Fuction模块(C MEX S-Function)》 见《开箱报告,Simulink Toolbox库模块使用指南(六)——S-Fuction模块(TLC)》 见《开…

Python学习:注释和运算符

python 注释 在Python中,注释用于在代码中添加解释、说明或者提醒,但并不会被解释器执行。Python中的注释以#开头,直到行末为止。下面是关于Python注释的详细解释和举例: 单行注释:使用#符号在行的开头添加注释&…

Vue3:标签的ref属性用法

一、情景说明 我们在写前端页面的时候,肯定会遇到获取DOM内容的情况。 以往,我们是用原生的js方法去获取,如document.getXxxx 但是,这中方法会有个问题,如果父组件和子组件的id相同,则会出错。 在Vue3中&…

酷开科技聚焦大屏端数据研究,构建酷开系统深度挖掘大屏商业价值

中国所有的彩色大屏中,智能电视规模已经过半,OTT平台的数据价值越发引起人们关注。作为OTT行业的头部代表,酷开科技一直聚焦大屏端数据研究,目前已经形成一套基于大屏指数的智慧营销体系,让OTT大屏的数字营销化水平实现…

安装MySQL5.7.19 + 解决数据库乱码

文章目录 1.删除mysql服务 sc delete mysql2.解压到D:\mysql5.7下3.配置管理员环境变量4.D:\mysql5.7\mysql-5.7.19-winx64下创建my.ini1.创建文件2.文件内容 5.管理员打开cmd,切换到 D:\mysql5.7\mysql-5.7.19-winx64\bin6.输入 mysqld -install 安装mysql服务7.初…

2 使用GPU理解并行计算

2.1 简介 本章旨在对并行程序设计的基本概念及其与GPU技术的联系做一个宽泛的介绍。本章主要面向具有串行程序设计经验,但对并行处理概念缺乏了解的读者。我们将用GPU的基本知识来讲解并行程序设计的基本概念。 2.2 传统的串行代码 绝大多数程序员是在串行程序占据…

数学建模-邢台学院

文章目录 1、随机抽取的号码在总体的排序2、两端间隔对称模型 1、随机抽取的号码在总体的排序 10个号码从小到大重新排列 [ x 0 , x ] [x_0, x] [x0​,x] 区间内全部整数值 ~ 总体 x 1 , x 2 , … , x 10 总体的一个样本 x_1, x_2, … , x_{10} ~ 总体的一个样本 x1​,x2​,……

《圣斗士星矢》AI制作CG大电影欣赏

《圣斗士星矢》AI制作CG大电影欣赏 In the darkest corners of the universe, legends are born. 宇宙最幽暗的角落,传奇应运而生。 The gods of Olympus descend, bringing chaos and terror. 奥林匹斯众神降临,带来混乱与恐怖。 The armor of the Sain…

Java基础学习笔记二

Java的加载与执行 Java既是编译型语言又是解释型语言 question:为什么JVM可以跨平台执行 answer : Java虚拟机(JVM)之所以能够跨平台执行,是因为它在不同操作系统上提供了一个统一的运行环境,实现了Java程…

Spring Boot+Vue前后端分离项目如何部署到服务器

🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…

19.WEB渗透测试--抓包技术(下)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容:18.WEB渗透测试--抓包技术(上)-CSDN博客 Burp含义和内容参考&…

《算法王晓东》多处最优服务次序问题

多处最优服务次序问题 题目描述 设有n个顾客同时等待一项服务。顾客i需要的服务时间为ti, 1≤i≤n。共有s处可以提供此项服务。应如何安排n个顾客的服务次序才能使平均等待时间达到最小? 平均等待时间是n个顾客等待服务时间的总和除以n。 算法设计:对于给定的n个顾…

jvm的垃圾回收器以及触发full gc的场景

JVM(Java虚拟机)的垃圾回收器有很多种,主要包括以下几种: Serial收集器:串行收集器是最古老、最稳定的收集器。它使用单个线程进行垃圾收集工作,在进行垃圾回收时会暂停所有用户线程。 ParNew收集器&#…