Runloop是怎样进行线程保活
AFN 中的实现
在旧版本的AFN 中使用了 NSURLConnection 来发起并处理网络连接。
AFN 的做法是把网络请求的发起和解析都放在同一个子线程中进行,子线程默认不开启 runloop,它会向一个 C语言程序那样在运行完所有代码后退出线程。
而网络请求是异步的,这导致获取到请求数据时,线程已经退出,代理方法没有机会执行。
因此,AFN 的做法是使用一个 runloop 来保证线程不死,也就是下面这段被讲烂了的代码:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@“AFNetworking”];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
稍微结合一下上下文,看看这个方法在哪里被调用:
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
似乎这种写法提供了一种思路:“如果需要在子线程中异步执行操作,可以利用 runloop 进行线程保活”。但准确的来说,AFN 的这种写法并不能实现我们的需求,它只是在 AFN 这个特殊场景下可以工作。
NSThread 与内存泄漏
这种写法的第一个问题就是存在内存泄漏。我们构造以下用例,把 AFN 的线程创建放在一个循环里:
- (void)memoryTest {
for (int i = 0; i 《 100000; ++i) {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
}
}
- (void)run {
@autoreleasepool {
NSLog(@“current thread = %@”, [NSThread currentThread]);
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
if (!self.emptyPort) {
self.emptyPort = [NSMachPort port];
}
[runLoop addPort:self.emptyPort forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
奇怪的事情出现了,尽管是在 ARC 环境下,内存依然不停的上涨。如果我们把 run 方法中和 runloop 相关的代码删除则不会出现上述问题,显然,开启 runloop 导致了内存泄漏,也就是 thread 对象无法释放。
非常好我支持^.^
(1) 100%
不好我反对
(0) 0%
下载地址
Runloop是怎样进行线程保活下载
相关电子资料下载
- 一文详解ZGC关键技术 26
- AMD推出锐龙 Threadripper 7000系列处理器 171
- 如何使用pthread_barrier_xxx系列函数来实现多线程之间的同步? 29
- SpringBoot物理线程、虚拟线程、Webflux性能比较 37
- SV线程的使用和控制 121
- Python 如何获取旅游景点信息 82
- 新一轮制裁,摩尔线程、壁仞等IC公司上实体清单,英伟达AI芯片限制出售! 927
- 英伟达H800和A800将禁运!美国将摩尔线程、壁仞列入贸易管制“黑名单” 301
- i9-14900K/i7-14700K处理器首发评测 134
- 酷睿i7-14700K处理器性能测试分析 115