iOS ------ autoreleasePool

news2024/11/26 11:42:37

一,@autoReleasePool{}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    
    }
    return 0;
}

我们平时创建一个main函数的代码的时候,就会发现其中有一个这个东西@autoreleasepool{},使用clang编译之后:@autoreleasepool{…}被编译成了{__AtAutoreleasePool __autoreleasepool; … }。

__AtAutoreleasePool到底是什么?

struct __AtAutoreleasePool {
    // 构造函数
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
    // 析构函数
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};

它其实是一个结构体,在创建__AtAutoreleasePool结构体变量的时候调用了objc_autoreleasePoolPush(void),销毁的时候会调动objc_autoreleasePoolPop(void *),分别是构造函数和析构函数,所以我们可以看出其其实是一个C++封装的自动释放池变量,会将@autoreleasepool{…}中{}中的内容添加到自动释放池中,方便内存管理。

二,AutoreleasePoolPage

从上边的__AtAutoreleasePool我们可以看到这两个方法objc_autoreleasePoolPushobjc_autoreleasePoolPop

void *objc_autoreleasePoolPush(void) {
    return AutoreleasePoolPage::push();
}
 
void objc_autoreleasePoolPop(void *ctxt) {
    AutoreleasePoolPage::pop(ctxt);
}

这里又引入了新的类AutoreleasePoolPage

class AutoreleasePoolPage {
    magic_t const magic;//AutoreleasePoolPage 完整性校验
    id *next;//存放下一个autorelease对象的地址
    pthread_t const thread; //AutoreleasePoolPage 所在的线程
    AutoreleasePoolPage * const parent;//父节点
    AutoreleasePoolPage *child;//子节点
    uint32_t const depth;//深度,也可以理解为当前page在链表中的位置
    uint32_t hiwat;
}
  • 其实自动释放池(即所有的AutoreleasePoolPage对象)其实就是一个由AutoreleasePoolPage构成的双向链表。
  • 每个AutoreleasePoolPage对象占用4096字节内存,其中56个字节用来存放它内部的成员变量,剩下的空间用来存放autorelease对象的地址。

在这里插入图片描述

  • 调用push()方法,往自动释放池中添加一个POOL_BOUNDARY,并返回它存放的内存地址;接着每有一个对象调用autorelease方法,会将它的内存地址添加进自动释放池中。
  • 会调用pop方法的传参token即为POOL_BOUNDARY对应在Page中的地址。当销毁自动释放池时,会调用pop()方法将自动释放池中的autorelease对象全部释放(实际上是从自动释放池的中的最后一个入栈的autorelease对象开始,依次给它们发送一条release消息,直到遇到这个POOL_BOUNDARY

讲一下POOL_BOUNDARY

  • POOL_BOUNDARY的前世叫做POOL_SENTINEL,称为哨兵对象或者边界对象;
  • POOL_BOUNDARY用来区分不同的自动释放池,以解决自动释放池嵌套的问题;

Autoreleasepool嵌套探究

单个page嵌套(autorelease对象较少)

由于ARC环境下不能调用autorelease等方法,所以需要将工程切换为MRC环境。

int main(int argc, const char * argv[]) {
    _objc_autoreleasePoolPrint();             // print1
    @autoreleasepool { //r1 = push()
        _objc_autoreleasePoolPrint();         // print2
        NSObject *p1 = [[[NSObject alloc] init] autorelease];
        NSObject *p2 = [[[NSObject alloc] init] autorelease];
        _objc_autoreleasePoolPrint();         // print3
        @autoreleasepool { //r2 = push()
            NSObject *p3 = [[[NSObject alloc] init] autorelease];
            _objc_autoreleasePoolPrint();     // print4
            @autoreleasepool { //r3 = push()
                NSObject *p4 = [[[NSObject alloc] init] autorelease];
                _objc_autoreleasePoolPrint(); // print5
            } //pop(r3)
            _objc_autoreleasePoolPrint();     // print6
        } //pop(r2)
        _objc_autoreleasePoolPrint();         // print7
    } //pop(r1)
    _objc_autoreleasePoolPrint();             // print8
    return 0;
}

autorelease对象的进出栈流程图如下所示。它们的作用域只在@autoreleasepool{}之间,超出之后就全部调用pop释放。

在这里插入图片描述

印证了上面的push和pop方法和POOL_BOUNDARY的原理

多个page嵌套(autorelease对象较少)

int main(int argc, const char * argv[]) {
    @autoreleasepool { //r1 = push()
        for (int i = 0; i < 600; i++) {
            NSObject *p = [[[NSObject alloc] init] autorelease];
        }
        @autoreleasepool { //r2 = push()
            for (int i = 0; i < 500; i++) {
                NSObject *p = [[[NSObject alloc] init] autorelease];
            }
            @autoreleasepool { //r3 = push()
                for (int i = 0; i < 200; i++) {
                    NSObject *p = [[[NSObject alloc] init] autorelease];
                }
                _objc_autoreleasePoolPrint();
            } //pop(r3)
        } //pop(r2)
    } //pop(r1)
    return 0;
}

一个AutoreleasePoolPage对象的内存大小为4096个字节,它自身成员变量占用内存56个字节,所以剩下的4040个字节用来存储autorelease对象的内存地址。又因为64bit下一个OC对象的指针所占内存为8个字节,所以一个Page可以存放505个对象的地址。

当一个page满的时候,会创建一个新的page,并且每个page之间是以栈为结点通过双向链表的形式组合而成。

在这里插入图片描述

autorelease和RunLoop

iOS在主线程RunLoop中注册了两个Observer

  • 第1个Observer监听了kCFRunLoopEntry事件,在即将进入RunLoop时,会调用objc_autoreleasePoolPush(),自动创建一个__AtAutorreleasePool结构体对象。
  • 第2个Observer
    • ① 监听了kCFRunLoopBeforeWaiting事件,RunLoop即将休眠时,会调用objc_autoreleasePoolPop()objc_autoreleasePoolPush();释放旧的池,创建新的池。
    • ② 监听了kCFRunLoopBeforeExit事件,RunLoop即将退出时,会调用objc_autoreleasePoolPop()释放自动释放池。

在这里插入图片描述

总结:

  • 自动释放池本质是一个AutoReleasePoolPage结构体对象,是一个栈结构存储的页,每一个AutoReleasePoolPage都是一个双向链表的形式连接。
  • 自动释放池的压栈和出栈主要是通过__AtAutoreleasePool的构造函数和析构函数objc_autoreleasePoolPushobjc_autoreleasePoolPop
  • 调用push操作就是创建一个新的AutoreleasePoolPage,对AutoreleasePoolPage的具体操作就是插入一个哨兵,并返回插入哨兵POOL_BOUNDARY的内存地址,每有对象调用autorelease方法,会将对象的内存地址添加进page中。
  • 调用pop操作的时候,传入的参数就是push返回的哨兵POOL_BOUNDARY的内存地址token,从自动释放池最后pushautorelease对象开始依次release释放掉,直到遇到哨兵POOL_BOUNDARY

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

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

相关文章

对《国家汽车芯片标准体系建设指南》好奇,遂读

基础通用&#xff1a;基于汽车行业对芯片的可靠性、运行稳定性 和安全性等应用需求&#xff0c;提取出汽车芯片性通用要求&#xff0c;主要包括环境及可靠性、电磁兼容、功能安全和信息安全共4个方面的要求。 产品与技术应用&#xff1a;根据实现功能的不同&#xff0c;将汽车…

文献综述能否帮助研究人员认识特定学术领域的趋势和新兴主题

VersaBot一键生成文献综述 进行良好的文献综述可以成为研究人员识别特定学术领域的趋势和新兴主题的强大工具。就是这样; 1. 识别模式和重复出现的概念&#xff1a; 当您深入研究现有研究时&#xff0c;您自然会开始注意到不同研究中采用的重复出现的主题、想法和方法。这些模…

详解爬虫使用代理ip的几种方案

​ 在如今这个信息爆炸的时代&#xff0c;数据就是财富。对于许多从事数据分析、市场调研和大数据处理的人来说&#xff0c;网络爬虫已经成为了他们的得力助手。然而&#xff0c;随着网站对爬虫的防范措施越来越严格&#xff0c;使用代理IP已经成为了爬虫工作中的一项必备技能。…

05:【stm32】重映射AFIO

重映射AFIO 1、什么是AFIO2、怎么使用AFIO 1、什么是AFIO AFIO是stm32上的众多片上外设之一&#xff0c;专门用来执行“复用功能的重映射” 2、怎么使用AFIO 如下图所示&#xff1a;当我们要同时使用USART1和TIM1时&#xff0c;我们就需要使用AFIO进行使其中一个片上外设进行重…

【iOS】SideTable

目录 SideTablesStripedMapSideTable1. spinlock_t slock2. RefcountMap3. weak_table_t 总结 objc4源码地址&#xff1a; SideTable& table SideTables()[this]; // 获取对象的SideTable size_t& refcntStorage table.refcnts[this];SideTables 查源码SideTables…

Android 多语言切换

文章目录 在系统设置修改语言创建资源目录创建资源文件示例验证 代码手动切换语言在Application中设置新的语言环境在MainActivity / BaseActivity中设置新的语言环境验证 问题1. makeText()方法context传入是Application的context&#xff0c;无法获取正确的资源字符串原因解决…

Docker + Nacos + Spring Cloud Gateway 实现简单的动态路由配置修改和动态路由发现

1.环境准备 1.1 拉取Nacos Docker镜像 从Docker Hub拉取Nacos镜像&#xff1a; docker pull nacos/nacos-server:v2.4.01.2 生成密钥 你可以使用命令行工具生成一个不少于32位的密钥。以下是使用 OpenSSL 生成 32 字节密钥的示例&#xff1a; openssl rand -base64 321.3 …

免费插件集-illustrator插件-Ai插件-选择路径等分

文章目录 1.介绍2.安装3.通过窗口>扩展>知了插件4.功能解释5.总结 1.介绍 本文介绍一款免费插件&#xff0c;加强illustrator使用人员工作效率&#xff0c;路径处理功能&#xff0c;功能是选择路径等分。首先从下载网址下载这款插件 https://download.csdn.net/download…

本地Gitlab-runner自动编译BES项目

0 Preface/Foreword 1 Gitlab-runner配置情况 具体情况如下&#xff1a; Gitlab-ruuner运行在wsl 1中的Ubuntu 18.04 distro上专门为GitLab-runner分配了一个用户&#xff0c;名为gitlab-runner 2 自动编译 2.1 找不到编译工具链 根据错误提示&#xff0c;交叉编译工具链未找…

Springboot利用大模型实现即时通信

gitee地址&#xff1a;https://gitee.com/myha/Springboot-langchain-chat 版本及工具说明 本项目版本&#xff1a;springboot3.2.8 jdk17 mybatis-plus3.5.7 安装python&#xff0c;可以参考&#xff1a;https://docs.python.org/zh-cn/3/using/windows.html#the-full-in…

zsh 配置 docker 自动补全

zsh 配置 docker 自动补全 在终端中使用 docker 的命令的时候必须要全部手敲&#xff0c;没有提示&#xff0c;于是就在找是否有自动补全的脚本&#xff0c;搜索了一圈踩了一些坑总结了一下具体的步骤。 首先执行如下命令&#xff1a; mkdir -p ~/.zsh/completion curl -L h…

Visual Studio创建 OpenCV项目

1、cmake 编译 opencv 参考链接&#xff1a;CMake编译OpenCV3.4.1心得_cmake 3.4.1-CSDN博客 1&#xff09;opencv文件名最好不要有空格 2&#xff09;没有下载opencv_contrib&#xff0c;不用配置OPENCV_EXTRA_MODULES_PATH 1、Visual Studio创建 OpenCV项目 参考链接&am…

esp32通过smartconfig连接wifi

esp32通过smartconfig连接wifi整体设计流程 1.流程图 2.代码实现 #include <WiFi.h> #include <SPIFFS.h>// 定义存储文件的文件名 const char* wifi_config_file "/wifi_config.txt";// 定义变量存储 WiFi 信息 // 1&#xff09;不填写为空时通过sma…

LangGraph Studio

文章目录 一、关于 LangGraph Studio下载 二、设置三、打开一个项目三、调用图开始新的运行配置图运行 四、创建和编辑线程1、创建一个线程2、选择一个线程3、编辑线程状态 五、如何向图表添加中断1、将中断添加到节点列表2、向特定节点添加中断 六、Human-in-the-loop七、编辑…

多模态大模型intern-vl 1.5 论文解读:How Far Are We to GPT-4V?

论文&#xff1a;https://arxiv.org/pdf/2404.16821 目录 1 介绍 3.1 整体架构 3.2 强大的视觉编码器 InternViT-6B-448px-V1.2 InternViT-6B-448px-V1.5 3.3 动态高分辨率 动态宽高比匹配 图像分割与缩略图 InternVL 1.5&#xff0c;这是一款开源的多模态大语言模型&…

Onenet服务器创建产品和设备

Onenet服务器创建产品和设备 (1)浏览器搜索 Onenet, 或者打开这个网址 OneNET - 中国移动物联网开放平台 (10086.cn) (2)登录注册, 密码特殊符号是 (3)进入此网址, 设备管理页面 设备列表 - OneNET物联网平台 (10086.cn) (4)点击产品开发,创建产品 (5)其他行业 (6)设备接…

功能管理之语录管理功能开发(八)

云风网 云风笔记 云风知识库 这里话不多说&#xff0c;直接上效果图,开发逻辑和专栏上篇用户管理大致相同

【JVM基础12】——垃圾回收-说一下JVM有哪些垃圾回收器?

目录 1- 引言&#xff1a;垃圾回收器2- ⭐核心&#xff1a;垃圾回收器详解2-1 串行垃圾回收器2-2 并行垃圾回收器2-3 CMS&#xff08;并发垃圾回收&#xff09;——主要作用在老年代 3- 小结3-1 说一下JVM有哪些垃圾回收器&#xff1f; 1- 引言&#xff1a;垃圾回收器 在 JVM …

人在职场,一半清醒,一半糊涂

职场如战场&#xff0c;同事之间&#xff0c;除了利益竞争&#xff0c;鲜有情谊。 想要扎根立足&#xff0c;学会清醒做事&#xff0c;糊涂做人&#xff0c;才有可能避免“踩坑”&#xff0c;行稳致远。 01 人在职场&#xff0c;清醒做事&#xff0c;才不会被排挤出局。 职…

Fluent Mybatis

官方文档&#xff1a;https://gitee.com/fluent-mybatis/fluent-mybatis/wikis 新的ORM框架&#xff0c;整个设计理念非常符合工程师思维。 Fluent Mybatis 介绍 何为 Fluent Mybatis&#xff1f; Fluent Mybatis, 是一款 Mybatis 语法增强框架, 综合了 Mybatis Plus, Dynam…