iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >iOS中多线程的经典崩溃有哪些
  • 782
分享到

iOS中多线程的经典崩溃有哪些

2023-06-04 21:06:41 782人浏览 八月长安
摘要

本篇内容介绍了“iOS中多线程的经典崩溃有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Block 回调的崩溃在MRC环境下,使用Blo

本篇内容介绍了“iOS多线程的经典崩溃有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

Block 回调的崩溃

在MRC环境下,使用Block 来设置下载成功的图片。当self释放后,weakSelf变成野指针,接着就悲剧了

__block ViewController *weakSelf = self;
[self.imageView imageWithUrl:@"" completedBlock:^(UIImage *image, NSError *error) {
NSLog(@"%@",weakSelf.imageView.description);
}];

线程下Setter 的崩溃

Getter & Setter 写多了,在单线程的情况下,是没有问题的。但是在多线程的情况下,可能会崩溃。因为[_imageView release]; 这段代码可能会被执行两次,oops!

UIKit 不是线程,所以在不是主线程的地方调用UIKit 的东西,有可能在开发阶段完全没问题,直接免测。但是一到线上,崩溃系统可能都是你的崩溃日志。Holy shit!

解决办法:通过hook 住setNeedsLayout,setNeedsDisplay,setNeedsDisplayInRect来检查当前调用的线程是否是主线程。

-(void)setImageView:(UIImageView *)imageView
{
if (![_imageView isEqual:imageView])
{
[_imageView release];
_imageView = [imageView retain];
}
}

更多Setter 类型的崩溃

property 的属性,写的最多的就是nonatomic,一般情况下也是没有问题的!

@interface ViewController ()
@property (strong,nonatomic) NSMutableArray *array;
@end

跑一下下面这段代码,你会看到:

malloc: error for object 0x7913D6d0: pointer being freed was not allocated

for (int i = 0; i < 100; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.array = [[NSMutableArray alloc] init];
});
}

原因就是:对象被重复relaese 了。查看一下runtime 源码

iOS中多线程的经典崩溃有哪些

解决办法:属性声明为atomic.

一个更为常见的例子:

if(handler == nil)
{
hander = [[Handler alloc] init];
}
return handler;

如果A,B两个线程同时访问到if语句, 此时handler == nil条件满足, 两个线程都走到下一句初始化实例.

此时A线程先完成初始化并赋值(这个实例我们叫它a), 然后继续往后走到其他逻辑.而这时候, B线程开始做初始化并赋值(这个实例我们叫它b), handler将指向B线程初始化出来的对象. 而A初始化出来的实例a因为引用计数减少1(减少到0)而被释放. 但在A线程中, 代码还会尝试访问a所在的地址, 这个地址里的内容因为被释放而变得无法预测, 从而导致野指针.

问题还有一个很关键的点, 在一个对象的某个方法的调用过程中, 这个对象的引用计数并不会增加, 到导致它如果被释放, 后续的执行过程中对这个对象的访问就可能会导致野指针[1].

Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR at 0x12345678
Triggered by Thread: 1

简单加个就可以解决问题了:

@synchronized(self){
if(handler == nil)
{
hander = [[Handler alloc] init];
}
}
return handler;

多线程下对变量的存取

if (self.xxx) {
[self.dict setObject:@"ah" forKey:self.xxx];
}

大家第一眼看到这样的代码,是不是会认为是正确的?因为在设置key的时候已经提前进行了self.xxx为非nil的判断,只有非nil得情况下才会执行后续的指令。但是,如上代码只有在单线程的前提下才是正确的。

假设我们将上述代码目前执行的线程为Thread A,当我们执行完if (self.xxx)的语句之后,此时CPU将执行权切换给了Thread B,而这个时候Thread B中调用了一句self.xxx = nil。 使用局部变量可以解决这个问题

__strong id val = self.xxx;
if (val) {
[self.dict setObject:@"ah" forKey:val];
}

这样,无论多少线程尝试对self.xxx进行修改,本质上的val都会保持现有的状态,符合非nil的判断。

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:519832104 不管你是小白还是大牛欢迎入驻,分享经验,讨论技术,大家一起交流学习成长!

另附上一份各好友收集的大厂面试题,需要iOS开发学习资料、面试真题,可以添加iOS开发进阶交流群,进群可自行下载!

iOS中多线程的经典崩溃有哪些

dispatch_group 的崩溃

dispatch_group_enter 和 leave 必须是匹配的,不然就会crash . 在多资源下载的时候,往往需要使用多线程并发下载,全部下载完之后通知用户。开始下载,dispatch_group_enter ,下载完成dispatch_group_leave 。 非常简单的流程,但是当代码复杂到一定程度或者是使用了一些第三方库的时候,就很大可能出问题。

dispatch_group_t serviceGroup = dispatch_group_create();
dispatch_group_notify(serviceGroup, dispatch_get_main_queue(), ^{
NSLog(@"Finish downloading :%@", downloadUrls);
});
// t 是一个包含一堆字符串数组
[downloadUrls enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
dispatch_group_enter(serviceGroup);
SDWEBImageCompletionWithFinishedBlock completion =
^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
dispatch_group_leave(serviceGroup);
NSLog(@"idx:%zd",idx);
};
[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString: downloadUrls[idx]] options:SDWebImageLowPriority progress:nil completed:completion];
}];

使用多线程进行并发下载,直到所有图片都下载完成(可以失败)进行回调,其中图片下载使用的是SDWebImage.发生崩溃的场景是:有10 张图片,分开两次下载(A & B)。其中在B组里面有一张图片和A组下载的图片重复了。假设A组下载对应GroupA ,B组GroupB

下面截取SDWebImage源码:

dispatch_barrier_sync(self.barrierQueue, ^{
SDWebImageDownloaderOperation *operation = self.URLOperations[url];
if (!operation) {
operation = createCallback();
// ****注意这行****
self.URLOperations[url] = operation;
__weak SDWebImageDownloaderOperation *woperation = operation;
operation.completionBlock = ^{
SDWebImageDownloaderOperation *soperation = woperation;
if (!soperation) return;
if (self.URLOperations[url] == soperation) {
[self.URLOperations removeObjectForKey:url];
};
};
}
// ****注意这行****
id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
}

SDWebImage的下载器会根据URL做下载任务对应NSOperation映射,相同的URL会映射到同一个未执行的NSOperation。当A组图片下载完成后,相同的url 回调是 GroupB 而不是Group A。此时Group B的计数为1 。当B 组图片全部下载完后,结束计数为 5+1 。因为enter 的次数为5 ,leave 的次数为6 ,因此会崩溃!

最后一个持有者释放后的崩溃

对象A被 manager 持有,在A中调用[Manager removeObjectA]。A对象的retainCount -1, 当retainCount 等于零时,对象A已经开始释放了。在调用removeObjectA 后,紧接着调用[self doSomething] ,就会崩溃。

-(void)finishEditing
{
[Manager removeObject:self];
[self doSomething];
}

这种情况一般会发生在数组或者字典包含对象,而且是对象的最后持有者。当在对象处理不好,就会有上面的崩溃。还有一种情况就是,当数组或者字典里面的对象已经被释放了,当遍历数组或者取字典里面的值发生崩溃。这种情况,会让人很崩溃,因为有时候堆栈是这样的:

Thread 0 Crashed:
0 libobjc.A.dylib 0x00000001816ec160 _objc_release :16 (in libobjc.A.dylib)
1 libobjc.A.dylib 0x00000001816edae8 __ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv :508 (in libobjc.A.dylib)
2 CoreFoundation 0x0000000181f4c9fc __CFAutoreleasePoolPop :28 (in CoreFoundation)
3 CoreFoundation 0x0000000182022bc0 ___CFRunLoopRun :1636 (in CoreFoundation)
4 CoreFoundation 0x0000000181f4cc50 _CFRunLoopRunSpecific :384 (in CoreFoundation)
5 GraphiCSServices 0x0000000183834088 _GSEventRunModal :180 (in GraphicsServices)
6 UIKit 0x0000000187236088 _UIApplicationMain :204 (in UIKit)
7 Tmall4iPhone 0x00000001000b7ae4 main main.m:50 (in Tmall4iPhone)
8 libdyld.dylib 0x0000000181aea8b8 _start :4 (in libdyld.dylib)

产生这种堆栈可能的场景是:

释放Dictionary的时候,某个值(value)因为被其他代码提前释放变成野指针, 此时再次被释放触发Crash. 如果可以在每个Dictionary释放的时候, 把所有的key/value打出来, 如果某个key/value刚好被打出来之后, crash就发生了, 那么挂就挂在刚被打出来的key/value上.

对象的释放线程要和它处理事情的线程一致

对象A在主线程监听Notification事件,如果这个对象被其它线程释放了。此刻,如果对象A 正在执行notification 相关的操作,再访问对象相关资源就野指针了,发生crash.

perfORMSelector:withObject:afterDelay:

调用此方法,如果不是在主线程,那么必须要确保当前线程的ruuloop是存在的,performSelector_xxx_afterDelay 依赖runlopp才能执行。另外使用 performSelector:withObject:afterDelay:和 cancelPreviousPerformRequestsWithTarget组合的时候要小心。

  • afterDelay会增加receiver的引用计数,cancel则会对应减一

  • 如果在receiver的引用计数只剩下1 (仅为delay)时,调用cancel之后会立即销毁receiver,后续再调用receiver的方法就会crash

__weak typeof(self) weakSelf = self;
[NSObject cancelPreviousPerformRequestsWithTarget:self];
if (!weakSelf)
{
//NSLog(@"self被销毁");
return;
}
[self doOther];

“iOS中多线程的经典崩溃有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: iOS中多线程的经典崩溃有哪些

本文链接: https://www.lsjlt.com/news/240028.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • iOS中多线程的经典崩溃有哪些
    本篇内容介绍了“iOS中多线程的经典崩溃有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Block 回调的崩溃在MRC环境下,使用Blo...
    99+
    2023-06-04
  • iOS开发多线程下全局变量赋值崩溃原理详解
    目录问题 Demo崩溃原因崩溃路径验证方式其它测试问题 Demo 在多线程下同时给全局变量赋值时会发生崩溃: static NSObject *_instance; - (void)...
    99+
    2024-04-02
  • 海外多ip服务器崩溃的原因有哪些
    非常抱歉,由于您没有提供文章标题,我无法为您生成一篇高质量的文章。请您提供文章标题,我将尽快为您生成一篇优质的文章。...
    99+
    2024-05-23
  • qt程序异常崩溃的原因有哪些
    Qt程序异常崩溃的原因可能有以下几种:1. 内存错误:例如访问已释放内存、越界访问数组等。2. 线程问题:例如多个线程之间的竞争条件...
    99+
    2023-09-22
    qt
  • java中经典的JVM锁有哪些
    本篇内容介绍了“java中经典的JVM锁有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!synchronized synchr...
    99+
    2023-06-17
  • C语言的经典程序有哪些
    本篇内容介绍了“C语言的经典程序有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、C语言必背18个经典程序第一个------乘法表。用...
    99+
    2023-07-02
  • 云服务器崩溃的原因有哪些
    云服务器崩溃的原因有以下几种:1. 硬件故障:包括服务器硬件损坏、电源故障、硬盘故障等,这些故障可能导致服务器无法正常运行。2. 软...
    99+
    2023-08-22
    云服务器
  • 经典的进程调度算法有哪些
    这篇文章主要介绍“经典的进程调度算法有哪些”,在日常操作中,相信很多人在经典的进程调度算法有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”经典的进程调度算法有哪些”的疑惑...
    99+
    2024-04-02
  • 网站服务器崩溃的原因有哪些
    网站服务器崩溃的原因有:1、网站访问量暴增,超出服务器所承受的能力,导致网站服务器崩溃;2、硬件配置空间不足,导致网站服务器崩溃;3、网站服务器的连接数量超载,导致服务器崩溃;4、网站服务器遭受黑客入侵或网络恶意攻击破坏,导致服务器崩溃。具...
    99+
    2024-04-02
  • 有哪些经典的DOS命令
    这篇文章将为大家详细讲解有关有哪些经典的DOS命令,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。案例一、FC文件对比众所周知,在安装软件时,一般会在注册表中或多或少留下点什么,时间一长就会有...
    99+
    2023-06-13
  • win10系统崩溃修复的方法有哪些
    这篇文章主要讲解了“win10系统崩溃修复的方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“win10系统崩溃修复的方法有哪些”吧! ...
    99+
    2023-04-06
    win10
  • 有哪些经典的vbs脚本
    这篇文章主要讲解了“有哪些经典的vbs脚本”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“有哪些经典的vbs脚本”吧!文件下载(无回显)  echo iLocal ...
    99+
    2023-06-08
  • 导致服务器崩溃的原因有哪些
    导致服务器系统崩溃的原因有:1、服务器搭建的网站程序访问量突出暴增,超出服务器承受能力导致;2、网站服务器自身硬件配置空间、存储空间不足导致;3、网站服务器的连接数量超载导致;4、网站服务器遭受黑客入侵或网络恶意攻击破坏导致。具体内容如下:...
    99+
    2024-04-02
  • HTML5中经典动画工具有哪些
    这篇文章将为大家详细讲解有关HTML5中经典动画工具有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。 HTML5是设计师用来打造时尚网站...
    99+
    2024-04-02
  • win10任务栏频繁崩溃的原因有哪些
    Win10任务栏频繁崩溃的原因可能有以下几点:1. 系统错误或故障:任务栏可能会因为系统错误或故障而崩溃。这可能是由于未知的操作导致...
    99+
    2023-08-22
    win10
  • CSS的经典面试题有哪些
    这篇“CSS的经典面试题有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“CSS的经典面试题有哪些”文章吧。1、 介绍一下...
    99+
    2023-06-27
  • 轻量级服务器崩溃的原因有哪些
    轻量级服务器崩溃的原因有:1、系统出现故障,导致服务器崩溃,需要对轻量级服务器进行重启或重装系统;2、硬盘空间已满,导致轻量级服务器崩溃,需要对硬盘容量进行升级;3、在处理大数据时服务器的CPU性能不足,导致轻量级服务器崩溃;4、遭受网络攻...
    99+
    2024-04-02
  • 幻兽帕鲁服务器崩溃的原因有哪些
    幻兽帕鲁服务器崩溃的原因可能有以下几种: 硬件故障:服务器的硬件部件(如电源、硬盘、内存等)出现故障,导致服务器无法正常运行。 ...
    99+
    2024-04-09
    服务器 幻兽帕鲁服务器
  • HTML与CSS经典的知识有哪些
    本篇内容主要讲解“HTML与CSS经典的知识有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“HTML与CSS经典的知识有哪些”吧!margin和paddin...
    99+
    2024-04-02
  • JavaScript错误的经典问题有哪些
    这篇文章主要介绍“JavaScript错误的经典问题有哪些”,在日常操作中,相信很多人在JavaScript错误的经典问题有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaScript错误的经典问题...
    99+
    2023-06-27
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作