iOS - AutoreleasePool
1. 基本数据结构
// AutoreleasePool 的基本结构
struct AutoreleasePoolPage {static pthread_key_t const key = AUTORELEASE_POOL_KEY;magic_t const magic;id *next; // 指向下一个可存放对象的地址pthread_t const thread; // 所属线程AutoreleasePoolPage * const parent; // 双向链表结构AutoreleasePoolPage *child;uint32_t const depth;uint32_t hiwat;// 大小固定为 4096 字节(一个虚拟内存页的大小)static size_t const SIZE = PAGE_MAX_SIZE;
}
2. 存储结构
class AutoreleasePoolPage {AutoreleasePoolPage * const parent;AutoreleasePoolPage *child;// 存储空间id *begin() { return (id *) ((uint8_t *)this+sizeof(*this)); }id *end() { return (id *) ((uint8_t *)this+SIZE); }
}
2.2 哨兵对象
#define POOL_BOUNDARY nil // 池边界标记
static inline void *push() {id *dest = autoreleaseFast(POOL_BOUNDARY);return dest;
}
3. 线程关系
3.1 TLS存储
// 每个线程都有自己的 AutoreleasePool 栈
static pthread_key_t key;
static void tls_dealloc(void *p) {if (p == (void*)EMPTY_POOL_PLACEHOLDER) return;AutoreleasePoolPage *page = (AutoreleasePoolPage*)p;page->kill(); // 清理操作
}
3.2 线程本地存储初始化
void tls_init() {_objc_pthread_key = pthread_key_create(&_objc_pthread_destroyspecific);AutoreleasePoolPage::key = tls_create(&_objc_autoreleasepool_deallocate);
}
4. 对象管理
4.1 添加对象
static inline id *autoreleaseFast(id obj) {AutoreleasePoolPage *page = hotPage();if (page && !page->full()) {return page->add(obj);} else if (page) {return autoreleaseFullPage(obj, page);} else {return autoreleaseNoPage(obj);}
}
4.2 清理对象
void releaseAll() {// 释放所有autorelease对象AutoreleasePoolPage *page = this;while (page->child) page = page->child;do {page->releaseUntil(page->begin());} while ((page = page->parent));
}
5. 生命周期管理
5.1 创建时机
// 1. 显式创建
@autoreleasepool {// 代码块
}// 2. RunLoop 相关
void _wrapRunLoopWithAutoreleasePool(void) {@autoreleasepool {// RunLoop 逻辑}
}
5.2 释放时机
// 1. @autoreleasepool 块结束
{void *token = objc_autoreleasePoolPush();// ... objc_autoreleasePoolPop(token);
}// 2. RunLoop 迭代结束
void _runLoopIterationDidEnd() {objc_autoreleasePoolPop(currentPool);
}
6. 内存管理
6.1 页面管理
void *push() {id *dest;if (DebugPoolAllocation) {// ...debug code...}dest = autoreleaseFast(POOL_BOUNDARY);return dest;
}static inline void pop(void *token) {AutoreleasePoolPage *page;id *stop;page = pageForPointer(token);stop = (id *)token;page->releaseUntil(stop);
}
6.2 溢出处理
static id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page) {// 当前页满了,创建新页AutoreleasePoolPage *next = new AutoreleasePoolPage(page);page->child = next;return next->add(obj);
}
7. 特殊情况处理
7.1 嵌套池
@autoreleasepool { // 外层池NSString *str1 = @"1";@autoreleasepool { // 内层池NSString *str2 = @"2";} // str2 被释放
} // str1 被释放
7.2 异常处理
void unwinding_cleanup() {// 异常展开时确保 AutoreleasePool 正确清理AutoreleasePoolPage *page = hotPage();if (page) {pop(page->begin());}
}
8. 性能优化
8.1 快速路径
static inline id autorelease(id obj) {ASSERT(obj);id *dest __unused = autoreleaseFast(obj);return obj;
}
8.2 空间优化
// 使用一页虚拟内存(4KB)作为存储单元
#define PAGE_MAX_SIZE 4096
9. 最佳实践
9.1 手动管理
// 处理大量临时对象
for (int i = 0; i < largeNumber; i++) {@autoreleasepool {// 创建临时对象的代码}
}
9.2 子线程处理
dispatch_async(dispatch_get_global_queue(0, 0), ^{@autoreleasepool {// 子线程代码}
});
10. 注意事项
1. 内存峰值:
// 不好的做法
for (int i = 0; i < largeNumber; i++) {// 创建autorelease对象
} // 在循环结束才释放// 好的做法
for (int i = 0; i < largeNumber; i++) {@autoreleasepool {// 创建autorelease对象} // 每次迭代都释放
}
2. 线程安全:
// 每个线程维护自己的autoreleasepool栈
+ (void)threadEntryPoint {@autoreleasepool {// 线程代码}
}
3. RunLoop关系:
// RunLoop每次迭代都会创建和释放autoreleasepool
void runLoopMain() {while (running) {@autoreleasepool {// 一次RunLoop迭代runLoopIteration();}}
}
这里涵盖了AutoreleasePool 的主要实现细节和使用注意事项。理解这些内容对于正确使用AutoreleasePool和优化内存管理非常重要。
总结说明:
1. 每个AutoreleasePoolPage 存储了一个静态变量key和成员变量thread
2. 多线程共用一个 key 用于从 TLS 中获取当前线程的的 page 实例对象
3. 在 TLS 内部获取当前的线程,使用 key 从当前线程的一个哈希表中取出对应的 page
4. 一个线程可能有多个 page,TLS 存储双向链表中当前线程对应的最后一个page和key之间的映射
5. 成员变量 thread 用于判断遍历过程中的 page节点是否是当前线程的page,如果不是则跳过,向前跳一个节点(page)
相关文章:
iOS - AutoreleasePool
1. 基本数据结构 // AutoreleasePool 的基本结构 struct AutoreleasePoolPage {static pthread_key_t const key AUTORELEASE_POOL_KEY;magic_t const magic;id *next; // 指向下一个可存放对象的地址pthread_t const thread; // 所属线程AutoreleasePoolPage …...
1.CSS的复合选择器
1.1 什么是复合选择器 在CSS中,可以根据选择器的类型把选择器分为基础选择器和复合选择器,复合选择器是建立在基础选择器之上,对基础选择器进行组合形成的。 复合选择器可以更精准、更高效的选择目标元素(标签) 复…...
优质内容在个人IP运营中的重要性:以开源AI智能名片商城小程序为应用实例的深度探讨
摘要:在数字化时代,个人品牌(IP)的塑造与传播已成为各行各业提升影响力、吸引用户关注、促进商业转化的关键策略。优质内容作为连接个人IP与目标受众的桥梁,其在个人IP运营中的重要性不言而喻。本文旨在深入探讨优质内…...
Kafka性能测试
kafka是一个大数据消息队列(可以看做为缓存软件) 功能测试:能够读写数据 性能测试:1、测试生产者每秒往kafka写入的最大吞吐量 2、测试消费者每秒从kafka里获取消息最大吞吐量 硬件 3台物理机组成的kafka集群。 内存121G、24…...
解决Docker冲突问题
错误:docker-ce-cli conflicts with 2:docker-1.13.1-210.git7d71120.el7.centos.x86_64 错误:docker-ce conflicts with 2:docker-1.13.1-210.git7d71120.el7.centos.x86_64 您可以尝试添加 --skip-broken 选项来解决该问题 您可以尝试执行:…...
新手入门 React .tsx 项目:从零到实战
🚀 新手入门 React .tsx 项目:从零到实战 💻✨ 如果你是 React 新手,刚接触 .tsx 文件,不要担心!跟着这份指南,一步一步来,你很快就能上手了!👇 Ὅ…...
基于可信数据空间的企业数据要素与流通体系建设(附ppt 下载)
近期,可信数据空间会议召开。大数据系统软件国家工程研究中心总工程师王晨发表了题为《基于可信数据空间的企业数据要素与流通体系建设》主旨演讲。 篇幅限制,部分内容如下:...
二维数组:求最大元素及其所在的行坐标及列坐标(PTA)C语言
求出NM整型数组的最大元素及其所在的行坐标及列坐标(如果最大元素不唯一,选择位置在最前面的一个)。 函数接口定义: int fun(int array[N][M]) ; 注意:函数只需靠return返回最大元素的值, 行、列坐标通过…...
WebRtc01: 课程导学、框架介绍
应用 难点 课程大纲 学习收获 涉及内容 概述 用途 学习收获...
HQChart使用教程30-K线图如何对接第3方数据44-DRAWPIE数据结构
HQChart使用教程30-K线图如何对接第3方数据44-DRAWPIE数据结构 效果图DRAWPIEHQChart代码地址后台数据对接说明示例数据数据结构说明效果图 DRAWPIE DRAWPIE是hqchart插件独有的绘制饼图函数,可以通过麦语法脚本来绘制一个简单的饼图数据。 饼图显示的位置固定在右上角。 下…...
【cuda学习日记】2.2 使用2维网络(grid)和2维块(block)对矩阵进行求和
在2.0中进行了用一维网格和块对一维向量进行了求和。 在2.1中例化了二维的网格和块。 接下来进行2维网络(grid)和2维块(block)对矩阵进行求和。 #include <stdio.h> #include <stdlib.h> #include <time.h> #i…...
深度学习中CUDA环境安装教程
首先说明,本人是小白,一次安装,可能有不对的地方,望包含。 安装CUDA 因为我们是深度学习,很多时候要用到gpu进行训练,所以我们需要一种方式加快训练速度。 通俗地说,CUDA是一种协助“CPU任务分…...
IDEA的常用设置
目录 一、显示顶部工具栏 二、设置编辑区字体按住鼠标滚轮变大变小(看需要设置) 三、设置自动导包和优化导入的包(有的时候还是需要手动导包) 四、设置导入同一个包下的类,超过指定个数的时候,合并为*&a…...
【VUE+ElementUI】通过接口下载blob流文件设置全局Loading加载进度
下载Blob流文件,并以服务形式显示文件下载进度 1、下载接口 增加 config参数,并用...config将该属性加入到请求中; xxapi.js文件中设置downloadFile下载接口 // 下载文件 export function downloadFile(data, config) {return request({ur…...
算法的五个重要特性和4个基本标准
五个特性: 1、有穷性:一个算法必须执行有穷步后结束、 2、确定性:对于每种情况下所应执行的操作,在算法中都应该有确切的规定,不会产生二义性, 使得算法的执行者和阅读者都能明确其含义以及如何执行。 3、…...
svelte5中使用react组件
在svelet5中导入并使用react组件库 svelte5中使用react组件 svelte5中使用react组件 在svelet5中导入并使用react组件库, 示例项目地址:https://github.com/shenshouer/my-svelte-react 在svelte5中当前还有问题,无法将children传递到react中渲染 使用…...
iOS - 自定义引用计数(MRC)
自定义引用计数(Custom Reference Counting)是指类可以通过重写 retain/release 等方法来实现自己的引用计数管理机制。这通常用于特殊场景下的内存管理优化。 1. 判断是否使用自定义引用计数 inline bool objc_object::hasCustomRR() {// 检查类是否…...
北航现实场景无人机VLN新基准! OpenUAV:面向真实环境的无人机视觉语言导航,平台、基准与方法
作者:Xiangyu Wang, Donglin Yang, Ziqin Wang, Hohin Kwan, Jinyu Chen, Wenjun Wu1, Hongsheng Li, Yue Liao, Si Liu 单位:北京航空航天大学人工智能学院,香港中文大学多媒体实验室,感知与交互智能中心 原文链接:…...
OpenCV计算机视觉 08 图像的旋转
图像的旋转 下面是一张小猪佩奇的照片,请进行顺时针90度,逆时针90度,180度旋转 方法一:使用了 NumPy 库的 np.rot90() 函数来实现图像的旋转 np.rot90(img, k-1) 表示将输入的图像 img 顺时针旋转 90 度, np.rot90(…...
C++感受15-Hello STL 泛型启蒙
生鱼片和STL的关系,你听过吗?泛型编程和面向对象编程,它们打架吗?行为泛型和数据泛型,各自的目的是? 0 楔 俄罗斯生鱼片,号称俄罗斯版的中国烤鸭,闻名于世。其鱼肉,源于…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
