iOS - Objective-C 底层实现中的哈希表
1. 关联对象存储(AssociationsHashMap)
// 关联对象的哈希表实现
typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap;
typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMap;class AssociationsManager {static AssociationsHashMap *_map; // 全局关联对象表void set(id object, const void *key, id value) {// 双层 map:对象 -> (key -> value)AssociationsHashMap::iterator i = _map->find(object);if (i != _map->end()) {ObjectAssociationMap &refs = i->second;refs[key] = ObjcAssociation(value);}}
};// 特点:
// 1. 双层哈希表结构
// 2. 使用 DenseMap 实现
// 3. 支持动态扩容
注意事项:
- 需要考虑内存开销
- 多层查找可能影响性能
- 需要正确管理关联对象的生命周期
2. 引用计数表(RefcountMap)
// SideTable 中的引用计数表
class SideTable {RefcountMap refcnts; // 存储对象的引用计数void retain(id obj) {RefcountMap::iterator it = refcnts.find(obj);if (it != refcnts.end()) {it->second += SIDE_TABLE_RC_ONE;}}
};typedef objc::DenseMap<DisguisedPtr<objc_object>, size_t> RefcountMap;// 特点:
// 1. 使用 DenseMap 实现
// 2. Key 使用伪装指针
// 3. 需要频繁访问和修改
注意事项:
- 需要保证原子性操作
- 性能要求高
- 内存管理要谨慎
3. 弱引用表(weak_table_t)
// 弱引用哈希表
struct weak_table_t {weak_entry_t *weak_entries; // 哈希数组size_t num_entries; // 实际条目数uintptr_t mask; // 容量掩码uintptr_t max_hash_displacement; // 最大哈希偏移weak_entry_t *get(id referent) {// 使用哈希查找size_t begin = hash_pointer(referent) & mask;size_t index = begin;size_t hash_displacement = 0;while (weak_entries[index].referent != referent) {index = (index + 1) & mask;if (index == begin) break;hash_displacement++;}return &weak_entries[index];}
};// 特点:
// 1. 开放寻址法处理冲突
// 2. 使用线性探测
// 3. 记录最大偏移量
注意事项:
- 需要控制装载因子,避免性能下降
- 删除元素时需要特殊处理,避免破坏探测链
- 扩容时需要重新哈希所有元素
4. 方法缓存(cache_t)
// 类的方法缓存
struct cache_t {struct bucket_t *_buckets; // 哈希表mask_t _mask; // 容量掩码mask_t _occupied; // 已使用数量IMP imp(SEL sel) {// 使用哈希查找方法实现bucket_t *b = buckets();mask_t m = mask();return findMethod(b, m, sel);}
};// 特点:
// 1. 采用散列函数直接寻址
// 2. 缓存最近使用的方法
// 3. 固定大小,满了就清空重建
注意事项:
- 缓存满时会清空重建,而不是扩容
- 性能敏感,需要快速查找
- 线程安全问题需要特别注意
5. 性能优化
// 使用 DenseMap 优化内存使用
template <typename T, typename U, typename V>
class DenseMap {// 1. 开放寻址法处理冲突pair<iterator, bool> insert(const T& key, const U& value) {// 查找空位置unsigned index = findEmptyBucket(key);// 插入数据Buckets[index] = make_pair(key, value);}// 2. 自动扩容void grow() {unsigned NewSize = size() * 2;rehash(NewSize);}
};
6. 使用特点
6.1 线程安全
// 访问 map 时加锁保护
spinlock_t& lock = SideTables()[obj].lock;
lock.lock();
// 操作 map
lock.unlock();
6.2 内存管理
// 定期清理
void cleanup() {// 遍历并清理无效条目for (iterator it = map.begin(); it != map.end();) {if (it->second.expired()) {it = map.erase(it);} else {++it;}}
}
6.3 哈希优化
// 优化的哈希函数
static inline uint32_t ptr_hash(const void *key) {uintptr_t k = (uintptr_t)key;return (uint32_t)(k ^ (k >> 7));
}
主要使用场景总结:
- 关联对象存储
- 引用计数管理
- 弱引用表实现
- 方法缓存
- 性能优化
使用特点:
- 多采用 DenseMap 实现
- 注重性能优化
- 考虑线程安全
- 自动内存管理
- 哈希冲突处理
7. 实现差异
7.1 冲突处理
// 开放寻址法
void insert(Key key, Value value) {size_t index = hash(key) & mask;while (table[index] != empty) {index = (index + 1) & mask; // 线性探测}table[index] = value;
}// 链地址法
void insert(Key key, Value value) {size_t index = hash(key) & mask;table[index].push_back(value); // 添加到链表
}
7.2 扩容策略
// weak_table_t 的扩容
void grow() {// 当使用率超过 3/4 时扩容if (num_entries >= capacity * 3/4) {resize(capacity * 2);}
}// cache_t 的重建
void rebuild() {// 缓存满时直接清空重建clear();allocate(capacity);
}
7.3 内存管理
// DenseMap 的内存管理
template <typename Key, typename Value>
class DenseMap {// 使用连续内存pair<Key, Value> *Buckets;// 自动扩容void grow() {reallocate(NumEntries * 2);}
};
8. 性能考虑
8.1 查找效率
// 方法缓存优化
IMP cache_t::imp(SEL sel) {// 使用位运算优化mask_t index = (mask_t)(uintptr_t)sel & _mask;return _buckets[index].imp();
}
8.2 空间效率
// weak_table_t 的空间优化
struct weak_entry_t {union {struct {weak_referrer_t *referrers; // 动态数组};struct {weak_referrer_t inline_referrers[WEAK_INLINE_COUNT]; // 内联存储};};
};
总结:
- 不同场景选择不同的哈希表实现
- 需要权衡时间和空间效率
- 要考虑线程安全问题
- 注意内存管理和性能优化
- 合理处理哈希冲突
- 选择适当的扩容策略
相关文章:
iOS - Objective-C 底层实现中的哈希表
1. 关联对象存储(AssociationsHashMap) // 关联对象的哈希表实现 typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap; typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMa…...
什么是软件架构
什么是软件架构 程序员说,软件架构是要决定编写哪些C程序或OO类、使用哪些库和框架 程序经理说,软件架构就是模块的划分和接口的定义 系统分析员说,软件架构就是为业务领域对象的关系建模 配置管理员说,软件架构就是开发出来的…...

【Golang/nacos】nacos配置的增删查改,以及服务注册的golang实例及分析
前言 本文分析的实例来源于nacos在github上的开源仓库 nacos配置的增删查改 先具体来看一段代码,我将逐步分析每一段的作用 package mainimport ("fmt""time""github.com/nacos-group/nacos-sdk-go/clients""github.com/naco…...

RabbitMQ集群安装rabbitmq_delayed_message_exchange
1、单节点安装rabbitmq安装延迟队列 安装延迟队列rabbitmq_delayed_message_exchange可以参考这个文章: rabbitmq安装延迟队列-CSDN博客 2、集群安装rabbitmq_delayed_message_exchange 在第二个节点 join_cluster 之后,start_app 就会报错了 (CaseC…...

Linux UDP 编程详解
一、引言 在网络编程领域,UDP(User Datagram Protocol,用户数据报协议)作为一种轻量级的传输层协议,具有独特的优势和适用场景。与 TCP(Transmission Control Protocol,传输控制协议࿰…...

【2024年华为OD机试】(B卷,100分)- 计算最接近的数 (Java JS PythonC/C++)
一、问题描述 题目解析 我们需要找到一个下标 i,使得表达式 X[i] - X[i 1] - ... - X[i K - 1] 的结果最接近于数组的中位数。如果有多个 i 满足条件,则返回最大的 i。 关键点: 中位数计算: 将数组排序后,中位数…...
Pytorch 自学笔记(三):利用自定义文本数据集构建Dataset和DataLoader
Pytorch 自学笔记(三) 1. Dataset与DataLoader1.1 torch.utils.data.Dataset1.2 torch.utils.data.DataLoader Pytorch 自学笔记系列的第三篇。针对Pytorch的Dataset和DataLoader进行简单的介绍,同时,介绍如何使用自定义文本数据集…...

QT 使用QSqlTableModel对数据库进行创建,插入,显示
文章目录 效果图概述功能点代码分析初始数据插入数据数据显示 总结 效果图 概述 本案例用于对数据库中的数据进行显示等其他操作,其他表格筛选,过滤等功能可看此博客 框架:数据模型使用QSqlTableModel,视图使用QTableView&#x…...
如何学习Transformer架构
Transformer架构自提出以来,在自然语言处理领域引发了革命性的变化。作为一种基于注意力机制的模型,Transformer解决了传统序列模型在并行化和长距离依赖方面的局限性。本文将探讨Transformer论文《Attention is All You Need》与Hugging Face Transform…...

浅谈云计算22 | Kubernetes容器编排引擎
Kubernetes容器编排引擎 一、Kubernetes管理对象1.1 Kubernetes组件和架构1.2 主要管理对象类型 二、Kubernetes 服务2.1 服务的作用与原理2.2 服务类型 三、Kubernetes网络管理3.1 网络模型与目标3.2 网络组件3.2.1 kube-proxy3.2.2 网络插件 3.3 网络通信流程 四、Kubernetes…...
计算 SAMOut V3 在将词汇表从1万 增加到6千万的情况下能够减少多少参数
当我们将词汇表从 60,000,000(六千万)减少到 10,000 时,实际上是在缩小模型的词嵌入层及其共享的语言模型头(LM Head)的规模。这将导致参数量显著减少。我们可以通过以下步骤来计算具体的参数减少量。 参数量减少计算…...
03.选择排序
一、题目思路 选择排序是一种简单直观的排序算法。它的工作原理是:首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大ÿ…...

02_登录窗口
新建场景 重命名为GameRoot 双击GameRoot进入新场景 同样摄像机清除格式 删除平行光并关闭渲染灯光的天空盒 新建空节点重命名为GameRoot GameRoot为游戏的根节点 在整个游戏中都不会被删除 在游戏的根节点下创建UI的根节点Canvas 创建一个空节点 作为UI根节点下的 登录场景UI…...

NodeJS | 搭建本地/公网服务器 live-server 的使用与安装
目录 介绍 安装 live-server 安装方法 安装后的验证 环境变量问题 Node.js 环境变量未配置正确 全局安装的 live-server 路径未添加到环境变量 运行测试 默认访问主界面 访问文件 报错信息与解决 问题一:未知命令 问题二:拒绝脚本 公网配置…...

SystemUI 实现音量条同步功能
需求:SystemUI 实现音量条同步功能 具体问题 以前在SystemUI 下拉框添加了音量条控制,目前发现在SystemUI下拉框显示状态的情况下, 按键或者底部虚拟导航点击音量加减时候,SystemUI音量条不更新。 如下图:两个Syste…...

嵌入式知识点总结 C/C++ 专题提升(一)-关键字
针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。 目录 1.C语言宏中"#“和"##"的用法 1.1.(#)字符串化操作符 1.2.(##)符号连接操作符 2.关键字volatile有什么含意?并举出三个不同的例子? 2.1.并行设备的硬件寄存…...

基础入门-传输加密数据格式编码算法密文存储代码混淆逆向保护安全影响
知识点: 1、传输格式&传输数据-类型&编码&算法 2、密码存储&代码混淆-不可逆&非对称性 一、演示案例-传输格式&传输数据-类型&编码&算法 传输格式 JSON XML WebSockets HTML 二进制 自定义 WebSockets:聊天交互较常…...

几个Linux系统安装体验(续): 统信桌面系统
本文介绍统信桌面系统(uos)的安装。 下载 下载地址: https://www.chinauos.com/resource/download-professional 下载文件:本文下载文件名称为uos-desktop-20-professional-1070-amd64.iso。 下载注意事项:可直接下…...

算法日记6.StarryCoding P52:我们都需要0(异或)
一、题目 二、题解: 1、对于这道题,题意为让我们寻找一个数x使得 b[i]a[i]^x, 并且b[1]^b[2]^b[3]^ b[4]^b[5]....0 2、我们把b[i]给拆开,可以得到 3、又因为^满足结合律,因此,可以把括号给拆开 4、接着…...

【网络协议】RFC3164-The BSD syslog Protocol
引言 Syslog常被称为系统日志或系统记录,是一种标准化的协议,用于网络设备、服务器和应用程序向中央Syslog服务器发送日志消息。互联网工程任务组(IETF)发布的RFC 3164,专门定义了BSD Syslog协议的规范和实现方式。通…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...