RunLoop 和 autoreleasepool

  • RunLoop和线程的一一对应的,对应的方式是以key-value的方式保存在一个全局字典中
  • 主线程的RunLoop会在初始化全局字典时创建
  • 子线程的RunLoop会在第一次获取的时候创建,如果不获取的话就一直不会被创建
  • RunLoop会在线程销毁时销毁

在iOS应用启动后会注册两个Observer管理和维护AutoreleasePool。不妨在应用程序刚刚启动时打印currentRunLoop可以看到系统默认注册了很多个Observer,其中有两个Observer的callout都是** _ wrapRunLoopWithAutoreleasePoolHandler**,这两个是和自动释放池相关的两个监听。

第一个Observer会监听RunLoop的进入,它会回调objc_autoreleasePoolPush()向当前的AutoreleasePoolPage增加一个哨兵对象标志创建自动释放池。这个Observer的order是-2147483647优先级最高,确保发生在所有回调操作之前。

第二个Observer会监听RunLoop的进入休眠和即将退出RunLoop两种状态,在即将进入休眠时会调用objc_autoreleasePoolPop() 和 objc_autoreleasePoolPush() 根据情况从最新加入的对象一直往前清理直到遇到哨兵对象。而在即将退出RunLoop时会调用objc_autoreleasePoolPop() 释放自动自动释放池内对象。这个Observer的order是2147483647,优先级最低,确保发生在所有回调操作之后。

主线程的其他操作通常均在这个AutoreleasePool之内(main函数中),以尽可能减少内存维护操作(当然你如果需要显式释放【例如循环】时可以自己创建AutoreleasePool否则一般不需要自己创建)。

其实在应用程序启动后系统还注册了其他Observer(例如即将进入休眠时执行注册回调_UIGestureRecognizerUpdateObserver用于手势处理、回调为_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv的Observer用于界面实时绘制更新)和多个Source1(例如context为CFMachPort的Source1用于接收硬件事件响应进而分发到应用程序一直到UIEvent)。

在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。

自动释放池的创建和释放,销毁的时机如下所示

  • kCFRunLoopEntry; // 进入runloop之前,创建一个自动释放池
  • kCFRunLoopBeforeWaiting; // 休眠之前,销毁自动释放池,创建一个新的自动释放池
  • kCFRunLoopExit; // 退出runloop之前,销毁自动释放池

什么情况下需要创建自动释放池?

其实自动释放池存在的意义是为了延迟释放一些对象,延迟向对象发送release消息。在实际的开发中,有两种情况是需要手动创建自动释放池的。

1、在多线程中,因为子线程中可能会使用便利构造器等方法来创建对象(类方法),那么这些对象的释放只能放在自动释放池中,此时需要在子线程中添加自动释放池。

使用便利构造器等方法来创建对象autorelease的对象,需要制动释放池才能释放

主线程已经添加过自动释放池,在main函数里面。

2、就是如果一段代码里面(比如for循环)大量使用便利构造器创建对象,也需要手动添加自动释放池。

什么是便利构造器?

便利构造器在初始化方法的基础上前进了一⼩小步。封装了对象创建过程。

便利构造器是“+”方法,返回本类型的实例,方法名以类名开头,其实一些类中的静态方法也是便利构造器。

可以有0到多个参数。内部实现:封装了alloc和初始化方法。使用起来更加简洁。

默认主线的运行循环(runloop)是开启的,子线程的运行循环(runloop)默认是不开启的,也就意味着子线程中不会创建autoreleasepool,所以需要我们自己在子线程中创建一个自动释放池。(子线程里面使用的类方法都是autorelease,就会没有池子可释放,也就意味着后面没有办法进行释放,造成内存泄漏。)----在主线程中如果产生事件那么runloop才回去创建autoreleasepool,通过这个道理我们就知道为什么子线程中不会创建自动释放池了,因为子线程的runloop默认是关闭的,所以他不会自动创建autoreleasepool,需要我们手动添加

NSThread和NSOperationQueue开辟子线程需要手动创建autoreleasepool,GCD开辟子线程不需要手动创建autoreleasepool,因为GCD的每个队列都会自行创建autoreleasepool

RunLoop 和 autoreleasepool的更多相关文章

  1. Runloop与autoreleasePool联系

    autoreleasePool自动释放池,ARC模式下,苹果会自动进行内存管理,不需要我们手动去管理内存.这对于苹果开发者来说,省去了很多事情,不用再每天为了内存管理浪费掉宝贵的开发时间.大家都知道, ...

  2. 都在说RunLoop...... 到底什么是RunLoop?

    RunLoop(消息循环):说白了就是一种事件监听循环.就好比是一个while循环,监听到事件就起来,没有就休息. 介绍: 它可以在不同模式下进行切换,iOS有五种模式,其中UIInitializat ...

  3. iOS Runloop 消息循环

    介绍 Runloop是一种事件监听循环,可以理解成一个while死循环,监听到事件就起来,没有就休息. Runloop可以在不同模式下进行切换,iOS有五种模式,其中UIInitializationR ...

  4. iOS开发——高级篇——Runloop相关一

    一.什么是runLoop 1.说白了,runloop就是运行循环 2.runloop,他是多线程的法宝 通常来讲,一个线程一次只能执行一个任务,执行完之后就退出线程.但是,对于主线程是不能退出的,因此 ...

  5. runloop 小记

    一.什么是runLoop 1.说白了,runloop就是运行循环 2.runloop,他是多线程的法宝 通常来讲,一个线程一次只能执行一个任务,执行完之后就退出线程.但是,对于主线程是不能退出的,因此 ...

  6. iOS面试题 -总结 ,你的基础扎实吗?

    1.#import和#include的区别,@class代表什么? (1)#import指令是Object-C针对#include的改进版本,#import确保引用的文件只会被引用一次,这样你就不会陷 ...

  7. iOS 面试题搜集

    1.#import和#include的区别,@class代表什么? 2.浅拷贝和深拷贝区别是什么? 3.Objective-C中类别和类扩展的区别? 4.Objective-C堆和栈的区别? 5.内存 ...

  8. BAT面试的准备—iOS篇

    本文主要用于记录在准备BAT面试中关于iOS遇到的问题和做一些相关面试题的笔记 iOS网络层设计 1.网络层和业务层的对接设计 使用哪种交互模式来和业务层对接 : 使用Delegate为主,目的是为了 ...

  9. RunLoop 总结:RunLoop的应用场景(一)

    参考资料 好的书籍都是值得反复看的,那好的文章,好的资料也值得我们反复看.我们在不同的阶段来相同的文章或资料或书籍都能有不同的收获,那它就是好文章,好书籍,好资料.关于iOS 中的RunLoop资料非 ...

随机推荐

  1. [转载]C++中四种强制类型转换方式

    C++中四种强制类型转换方式 原文地址:http://www.cnblogs.com/home123/p/6763967.html 类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单( ...

  2. [TimLinux] 养成一个习惯

    1. 习惯 在博客园开博之前,大约六个月之前,我开始给自己定下坚持跑步的目标,从而养成了一个习惯.就在大约半个月前,回顾自己的工作经历的时候,发现还有一个来月自己就工作十年了,为此我树立了一个新的目标 ...

  3. CoderForces Round60-(1117A,1117B,1117C题解)

    A. Best Subsegment time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  4. redis(7)--redis应用实战

    问题1:哨兵模式下客户端应该连接哪个redis-server? 问题2:集群模式下为什么会有MOVED error Redis Java客户端介绍 已有的客户端支持 Redis Java客户端有很多的 ...

  5. 1.使用大clob入库出错问题

    在代码中调用pstm.setString(str) str>4000,这种大字符串插入时出现字符过长插入报错问题. 解决问题:用声明变量方式: <insert id ="inse ...

  6. 使用docker安装虚拟机并打开ssh连接

    一.需求 最近有个需求,要连接很多个linux系统进行测试软件功能,但是我这里只有几个虚拟机,所以需要使用docker来安装几十个或者上百个虚拟机来进行测试. 二.安装docker 这里就不演示怎么安 ...

  7. 牛客NOIP暑期七天营-提高组3

    第一题:破碎的矩阵 题目链接:https://ac.nowcoder.com/acm/contest/932/A    刚看到这题的时候感觉特别熟悉...诶,这不就是codeforces某场比赛的某某 ...

  8. springboot-eureka交流机制

    一 前言 这篇文章参考了官方文档,主要是描述了eureka client 和 eureka server 之间的交流机制: peer to peer 的 对等复制交流机制: eureka 官方文档 二 ...

  9. shell概述与echo命令

    一.Shell概述 1.什么是shell? 由此可见shell是用户与系统进行交互的接口,通过执行各种命令来完成时间处理与调度. 2.shell分类 Shell类别 易学性 可移植性 编辑性 快捷性 ...

  10. 在WPF中开启摄像头扫描二维码(Media+Zxing)

    近两天项目中需要添加一个功能,是根据摄像头来读取二维码信息,然后根据读出来的信息来和数据库中进行对比显示数据. 选择技术Zxing.WPFMediaKit.基本的原理就是让WPFmediaKit来对摄 ...