iOS - Tagged Pointer

news2025/1/11 19:16:42

1. 基本结构

// Tagged Pointer 的内存布局
union TaggedPointer {
    uintptr_t bits;  // 完整的指针值
    struct {
        uintptr_t data     : 60;  // 数据部分
        uintptr_t tag      : 4;   // 类型标记
    };
    
    // 扩展类型
    struct {
        uintptr_t extData  : 52;  // 扩展数据
        uintptr_t extTag   : 8;   // 扩展标记
        uintptr_t isExt    : 4;   // 是否是扩展类型
    };
};

2. 类型判断

// 判断是否是 Tagged Pointer
static inline bool 
isTaggedPointer(const void *ptr) {
    return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}

// 获取类型标记
static inline uintptr_t 
getTaggedPointerTag(const void *ptr) {
    return ((uintptr_t)ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_MASK;
}

3. 支持的数据类型

3.1 基本类型

// NSNumber 的 Tagged Pointer 实现
+ (NSNumber *)numberWithInt:(int)value {
    // 如果值在 Tagged Pointer 范围内
    if (value >= MIN_TAGGED_INT && value <= MAX_TAGGED_INT) {
        uintptr_t tagged = ((uintptr_t)value << 4) | NSNumberTag;
        return (__bridge id)(void *)tagged;
    }
    // 否则创建普通对象
    return [[NSNumber alloc] initWithInt:value];
}

3.2 字符串类型

// NSString 的 Tagged Pointer 实现
+ (NSString *)stringWithSmallString:(const char *)str {
    size_t length = strlen(str);
    if (length <= 7) {  // 可以用 Tagged Pointer 存储
        uintptr_t tagged = 0;
        for (size_t i = 0; i < length; i++) {
            tagged |= ((uintptr_t)str[i] << (i * 8));
        }
        tagged |= (NSStringTag << 60);  // 添加标记
        return (__bridge id)(void *)tagged;
    }
    return [[NSString alloc] initWithUTF8String:str];
}

4. 内存管理

4.1 引用计数

// Tagged Pointer 不需要引用计数
id objc_retain(id obj) {
    if (isTaggedPointer(obj)) return obj;
    return obj->retain();
}

void objc_release(id obj) {
    if (isTaggedPointer(obj)) return;
    return obj->release();
}

4.2 内存优化

// 直接存储数据,无需额外内存分配
+ (instancetype)optimizedNumberWithInt:(int)value {
    if (canBeTaggedPointer(value)) {
        return makeTaggedPointer(value);
    }
    return [self newNumberWithInt:value];
}

5. 消息发送

id objc_msgSend_tagged(id self, SEL _cmd, ...) {
    // 1. 获取类型标记
    uintptr_t tag = getTaggedPointerTag(self);
    
    // 2. 获取对应的类
    Class cls = objc_getTaggedPointerClass(tag);
    
    // 3. 查找方法
    IMP imp = lookUpImpOrForward(cls, _cmd);
    
    // 4. 调用方法
    return imp(self, _cmd, ...);
}

6. 性能优化

6.1 空间优化

// 普通对象
struct NSNumber {
    Class isa;
    int value;      // 至少需要 16 字节
};

// Tagged Pointer
// 直接使用指针存储值,只需要 8 字节
uintptr_t taggedNumber = (value << 4) | tag;

6.2 时间优化

// 普通对象访问
int getValue(NSNumber *num) {
    // 1. 解引用 isa
    // 2. 解引用获取值
    return num->_value;
}

// Tagged Pointer 访问
int getTaggedValue(NSNumber *num) {
    // 直接从指针中提取值
    return (uintptr_t)num >> 4;
}

7. 限制和注意事项

7.1 大小限制

// 数据大小限制
#define TAGGED_POINTER_MASK  0xF000000000000000
#define TAGGED_POINTER_DATA  0x0FFFFFFFFFFFFFFF

bool canBeTagged(size_t size) {
    // 60位数据位的限制
    return size <= (sizeof(uintptr_t) * 8 - 4);
}

7.2 类型限制

// Tagged Pointer 支持的类型定义
static Class taggedPointerClasses[] = {
    [OBJC_TAG_NSAtom]            = NSAtom,              // 0
    [OBJC_TAG_NSString]          = NSString,            // 1
    [OBJC_TAG_NSNumber]          = NSNumber,            // 2
    [OBJC_TAG_NSIndexPath]       = NSIndexPath,         // 3
    [OBJC_TAG_NSManagedObjectID] = NSManagedObjectID,   // 4
    [OBJC_TAG_NSDate]            = NSDate,               // 5
    [OBJC_TAG_NSDateTS]          = NSDateTS,             // 6
    [OBJC_TAG_NSDecimalNumber]   = NSDecimalNumber       // 7
};

8. 实际应用

8.1 字符串优化

NSString *str1 = @"abc";     // 可能使用 Tagged Pointer
NSString *str2 = @"这是一个很长的字符串";  // 普通对象

Tagged Pointer 的优势:

  1. 减少内存分配
  2. 提高访问速度
  3. 减少引用计数操作
  4. 优化内存使用

这种优化对于小对象的处理特别有效,是一个重要的性能优化手段。

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

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

相关文章

win32汇编环境,怎么进行乘法运算的

;运行效果 ;win32汇编环境,怎么进行乘法运算的 ;基础知识&#xff0c;重新复习一下。 ;首先需明白字节的概念。1个字节是8位&#xff0c;al和ah都是8位的&#xff0c;8位之中每位要么是0&#xff0c;要么是1&#xff0c;假如8位都是1&#xff0c;就是16进制的FF&#xff0c;也就…

opencv的NLM去噪算法

NLM&#xff08;Non-Local Means&#xff09;去噪算法是一种基于图像块&#xff08;patch&#xff09;相似性的去噪方法。其基本原理是&#xff1a; 图像块相似性&#xff1a;算法首先定义了一个搜索窗口&#xff08;search window&#xff09;&#xff0c;然后在该窗口内寻找…

poi处理多选框进行勾选操作下载word以及多word文件压缩

一、场景 将数据导出word后且实现动态勾选复选框操作 eg: word模板 导出后效果&#xff08;根据数据动态勾选复选框&#xff09; 二、解决方案及涉及技术 ① 使用poi提供的库进行处理&#xff08;poi官方文档&#xff09; ② 涉及依赖 <!-- excel工具 --><depen…

【update 更新数据语法合集】.NET开源ORM框架 SqlSugar 系列

系列文章目录 &#x1f380;&#x1f380;&#x1f380; .NET开源 ORM 框架 SqlSugar 系列 &#x1f380;&#x1f380;&#x1f380; 文章目录 系列文章目录前言 &#x1f343;一、实体对象更新1.1 单条与批量1.2 不更新某列1.3 只更新某列1.4 NULL列不更新1.5 无主键/指定列…

征战越南电商直播,SD - WAN 专线赋能企业带货新征程

在当今数字化商业浪潮中&#xff0c;越南电商市场正经历着蓬勃发展与激烈变革。根据 Sapo Technology Joint Stock Company 对全国 15,000 名卖家的深度调查&#xff0c;2024 年零售业务的直播领域呈现出多元竞争态势。Facebook Live 强势占据多渠道或仅在线销售卖家总直播会话…

Android Studio创建新项目并引入第三方jar、aar库驱动NFC读写器读写IC卡

本示例使用设备&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1bbW3AUC&ftt&id615391857885 一、打开Android Studio,点击 File> New>New project 菜单&#xff0c;选择 要创建的项目模版&#xff0c;点击 Next 二、输入项目名称…

创业企业如何吸引投资?-中小企实战运营和营销工作室博客

创业企业如何吸引投资&#xff1f;-中小企实战运营和营销工作室博客 创业企业吸引投资需要从多个方面入手&#xff0c;包括打磨自身项目、做好商业展示、拓展融资渠道、有效对接资本等&#xff0c;以下是具体的方法&#xff1a; 一&#xff1a;打磨创业项目 1&#xff0c;明…

donet (MVC)webAPI 的接受json 的操作

直接用对象来进行接收&#xff0c;这个方法还不错的。 public class BangdingWeiguiJiluController : ApiController{/// <summary>/// Json数据录入错误信息/// </summary>/// <param name"WeiguiInfos"></param>/// <returns></r…

备战蓝桥杯 链表详解

目录 链表概念 静态单链表的实现 静态双链表的实现 循环链表 算法题练习&#xff1a; 1.排队顺序 2.单向链表 3.队列安排 4.约瑟夫问题 链表概念 上一次我们用顺序存储实现了线性表&#xff0c;这次我们用链式存储结构实现的线性表就叫链表 链表每个节点包含数据本身…

灵活运用事务回滚,快捷处理多张数据表格

各位编程宝子们&#xff08;尤其是对MySQL了解不多的宝子们&#xff09;在使用关系表处理时&#xff0c;有时候会希望简单一次性解决多张表的数据处理&#xff0c;但又有时候无从下手。其实有时候掌握数据的事务和回滚便可以简单解决这些事情&#xff0c;接下来我将以一个学生信…

使用C# CEFSharp在WPF中开发桌面程序实现同一网站多开功能

在网络商业运营领域&#xff0c;同时运营多个淘宝店铺的现象屡见不鲜。为了满足这一需求&#xff0c;实现同一网址的多开功能变得尤为关键。这一需求虽然实用&#xff0c;但实现起来却面临诸多挑战。在这个过程中&#xff0c;技术人员们也经历了不少喜怒哀乐。 开发经历回顾 …

CompletableFuture // todo

相比较所有代码都在主线程执行&#xff0c;使用Future的好处&#xff1a;利用服务器多核、并发的优势。 不足&#xff1a; 开启没有返回值的异步线程&#xff1a; 1、runAsync 使用lambda表达式&#xff1a; 开启有返回值的异步线程&#xff1a; 1、supplyAsync 异步任务中的…

如何评价deepseek-V3 VS OpenAI o1 自然语言处理成Sql的能力

DeepSeek-V3 介绍 在目前大模型主流榜单中&#xff0c;DeepSeek-V3 在开源模型中位列榜首&#xff0c;与世界上最先进的闭源模型不分伯仲。 准备工作&#xff1a; 笔者只演示实例o1 VS DeepSeek-V3两个模型&#xff0c;大家可以自行验证结果或者实验更多场景&#xff0c;同时…

ASP.NET Core 实现微服务 - Consul 配置中心

这一次我们继续介绍微服务相关组件配置中心的使用方法。本来打算介绍下携程开源的重型配置中心框架 apollo 但是体系实在是太过于庞大&#xff0c;还是让我爱不起来。因为前面我们已经介绍了使用Consul 做为服务注册发现的组件 &#xff0c;那么干脆继续使用 Consul 来作为配置…

tdengine数据库使用java连接

1 首先给你的项目添加依赖 <dependency> <groupId>com.taosdata.jdbc</groupId> <artifactId>taos-jdbcdriver</artifactId> <version>3.4.0</version> <!-- 表示依赖不会传递 --> </dependency> 注意&am…

深入学习RabbitMQ的Direct Exchange(直连交换机)

RabbitMQ作为一种高性能的消息中间件&#xff0c;在分布式系统中扮演着重要角色。它提供了多种消息传递模式&#xff0c;其中Direct Exchange&#xff08;直连交换机&#xff09;是最基础且常用的一种。本文将深入介绍Direct Exchange的原理、应用场景、配置方法以及实践案例&a…

51单片机——串口通信(重点)

1、通信 通信的方式可以分为多种&#xff0c;按照数据传送方式可分为串行通信和并行通信&#xff1b; 按照通信的数据同步方式&#xff0c;可分为异步通信和同步通信&#xff1b; 按照数据的传输方向又可分为单工、半双工和全双工通信 1.1 通信速率 衡量通信性能的一个非常…

本地手集博客id“升级”在线抓取——简陋版——(2024年终总结1.1)

我之前每每发布笔记都用csv纯文本记录&#xff0c;一个机缘巧得文章列表api实现在线整理自已的文章阅读量数据。 (笔记模板由python脚本于2025年01月10日 18:48:25创建&#xff0c;本篇笔记适合喜欢钻牛角尖的coder翻阅) 【学习的细节是欢悦的历程】 Python官网&#xff1a;htt…

高等数学学习笔记 ☞ 洛必达法则与泰勒公式

1. 洛必达法则 1. 型与型未定式&#xff08;洛必达法则&#xff09; &#xff08;1&#xff09;型&#xff1a;若函数同时满足以下条件&#xff1a; &#xff08;2&#xff09;型&#xff1a;若函数同时满足以下条件&#xff1a; ①&#xff1a;当时&…

Qt官方下载地址

1. 最新版本 Qt官方最新版本下载地址&#xff1a;https://www.qt.io/download-qt-installer 当前最新版本Qt6.8.* 如下图&#xff1a; 2. 历史版本 如果你要下载历史版本安装工具或者源码编译方式安装&#xff0c;请转至此链接进行下载&#xff1a;https://download.qt.i…