【iOS】—— Tagged Pointer对象

news2024/11/26 16:25:55

文章目录

  • 关于Tagged Pointer
    • NSTaggedPointer示例
    • TaggedPointer 结构
    • Tagged Pointer特点
    • 注意事项
      • isa指针
      • 64位下的isa指针优化

本来打算细看一下weak的底层原理,看到了出现了很多次Tagged Pointer对象,就先来学一下Tagged Pointer,在之前刚学习OC的时候,学习NSString三种类型的时候,接触过这个类型,但是没有往下细看,现在来细看看:

关于Tagged Pointer

在2013年9月,苹果推出了iPhone5s,与此同时,iPhone5s配备了首 个采用64位架构的A7双核处理器,为了节省内存和提高执行效率,苹果提出了Tagged Pointer的概念。先看看原有的对象为什么会浪费内存。假设要存储一个NSNumber对象,其值是一个整数。正常情况下,如果这个整数只是一个NSInteger的普通变量,那么它所占用的内存是与CPU的位数有关,在32位CPU下占4个字节,在64位CPU下是占8个字节的。而指针类型的大小通常也是与CPU位数相关,一个指针所占用的内存在32位CPU下为4个字节,在64位CPU下也是8个字节。所以一个普通的iOS程序,如果没有Tagged Pointer对象,从32位机器迁移到64位机器中后,虽然逻辑没有任何变化,但这种NSNumberNSDate一类的对象所占用的内存会翻倍。

苹果对于Tagged Pointer特点的介绍:

Tagged Pointer专门用来存储小的对象,例如NSNumberNSDate
Tagged Pointer指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要mallocfree
在内存读取上有着3倍的效率,创建时比以前快106倍。

请添加图片描述

为了存储和访问一个NSNumber对象,我们需要在堆上为其分配内存,另外还要维护它的引用计数,管理它的生命期。这些都给程序增加了额外的逻辑,造成运行效率上的损失。
为了改进上面提到的内存占用和效率问题,苹果提出了Tagged Pointer对象。由于NSNumber、NSDate一类的变量本身的值需要占用的内存大小常常不需要8个字节,拿整数来说,4个字节所能表示的有符号整数就可以达到20多亿。所以我们可以将一个对象的指针拆成两部分,一部分直接保存数据,另一部分作为特殊标记,表示这是一个特别的指针,不指向任何一个地址。
请添加图片描述
于是,简单来讲可以理解为把指针指向的内容直接放在了指针变量的内存地址中,因为在 64 位环境下指针变量的大小达到了 8 位足以容纳一些长度较小的内容。于是使用了标签指针这种方式来优化数据的存储方式。在运行时根据实际情况创建。
请添加图片描述

NSTaggedPointer示例

        NSString *string = nil;
        NSMutableString *mutableString = [NSMutableString stringWithFormat:@"abcde"];
        for (int i = 5; i < 15; i++) {
            [mutableString appendFormat:@"a"];
            string = [mutableString copy];
            NSLog(@"%@ %p %@", string, string, [string class]);
        }

输出结果:
在这里插入图片描述
当字符串的长度为10个以内时,字符串的类型都是NSTaggedPointerString类型,当超过10个时,字符串的类型才是__NSCFString

TaggedPointer 结构

苹果为了安全对其做了编码,runtime内部实现了编码、解码方法,我们看一下:
编码:

static inline void * _Nonnull
_objc_encodeTaggedPointer(uintptr_t ptr)
{
    uintptr_t value = (objc_debug_taggedpointer_obfuscator ^ ptr);
#if OBJC_SPLIT_TAGGED_POINTERS
    if ((value & _OBJC_TAG_NO_OBFUSCATION_MASK) == _OBJC_TAG_NO_OBFUSCATION_MASK)
        return (void *)ptr;
    uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
    uintptr_t permutedTag = _objc_basicTagToObfuscatedTag(basicTag);
    value &= ~(_OBJC_TAG_INDEX_MASK << _OBJC_TAG_INDEX_SHIFT);
    value |= permutedTag << _OBJC_TAG_INDEX_SHIFT;
#endif
    return (void *)value;
}

我们可以试着打印地址:

NSNumber *number1 = [NSNumber numberWithInt:1];
NSLog(@"number1 pointer is %p", number1);

输出结果:

number1 pointer is 0xbb027d74df7d32ea

可见,这个地址是被编码过的。通过资料的查询,我们可以对其结构有个了解:

  • Tagged Pointer 标记:x86最后一位是标记位,arm64最高位是标记位。1表示是Tagged Pointer对象,0表示是普通对象。
  • Tag:对象类型标记。x86为13位,arm64为02。7表示有扩展信息。
  • Extended:x86为411位,arm64为5462。用来扩展更多类型。
  • payload:有效负载。存储真正的数据(除了标记位、tag以及extended),不过为了安全苹果做了编码。

Tagged Pointer特点

我们也可以看到苹果对于Tagged Pointer 特点的介绍:

  • Tagged Pointer 专门用来存储小的对象,例如 NSNumber 和 NSDate。
  • Tagged Pointer 指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象
    了,它只是一个披着对象“皮”的普通变量而己。所以,它的内存并不存储在堆中,也
    不需要 malloc 和free。
  • 在内存读取上有着以前3倍的效率,创建时比以前快 106倍
    因此,苹果引入 Tagged Pointer,不但减少了 64位机器下程序的内存占用,还提高了运行效率,完美地解决了小内存对象在存储和访问效率上的问题。

注意事项

isa指针

Tagged Pointer 的引入也带来了问题,即 Tagged Pointer 并不是真正的对象,而是一个伪对象,所以你如果完全把它当成对象来使用,可能会让它“露马脚”。在上一章中我们写道,所有对象都有isa 指针,而 Tagged Pointer 其实是没有的,因为它不是真正的对象。

64位下的isa指针优化

对于 64位设备,苹果除了引人 Tagged Pointer 来优化小的对象外,对于普通的对象,其isa指针也进行了优化和调整。在32 位环境下,对象的引用计数都保存在一个外部的表中,每一个对象的 Retain 操作,实际上包括如下 5个步骤:

  • 获得全局的记录引用计数的hash 表。
  • 为了线程安全,给该hash 表加锁。
  • 查找到目标对象的引用计数值。
  • 将该引用计数值加1,写回hash 表。
  • 给该hash 表解锁。

从上面的步骤我们可以看出,为了保证线程安全,对引用计数的增减操作都要先锁定这个表,这从性能上看是非常差的。
而在 64 位环境下,isa 指针也是64 位,实际作为指针部分只用到的其中33位,剩余的 31位苹果使用了类似 Tagged Pointer 的概念,其中 19 位将保存对象的引1用计数,这样对引用计数的操作只需要修改这个指针即可。只有当引用计数超出19位,才会将引用计数保存到外部表,而这种情况是很少的,所以这样引用计数的更改效率会更高。
与前面的5个步骤对应,在64位环境下,新的 Retain 操作包括如下 5个步骤:

  • 检查 isa 指针上面的标记位,看引1用计数是否保存在 isa变量中,如果不是,则使用以前
    的步骤,否则执行第2步
  • 检查当前对象是否正在释放,如果是,则不做任何事情。
  • 增加该对象的引用计数,但是并不马上写回到isa 变量中。
  • 检杳增加后的引用计数的值是否能够被 19 位表示,如果不是,则切换成以前的办法,否则执行第5步。
  • 进行一个原子的写操作,将isa 的值写回。

虽然步骤都是 5步,但是由于没有了全局的加锁操作,所以引用计数的更改更快了。

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

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

相关文章

chatgpt赋能python:Python隐藏CMD窗口

Python隐藏CMD窗口 Python是一种高级编程语言&#xff0c;已被广泛用于各种领域&#xff0c;从Web开发到数据科学。Python的一个非常有用的特性是它可以通过CMD窗口运行脚本&#xff0c;但在某些情况下&#xff0c;隐藏CMD窗口可能是必要的。 为什么要隐藏CMD窗口&#xff1f…

如何在华为OD机试中获得满分?Java实现【微服务的集成测试】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1、题目描述2、输入描述3、输出描述…

一图看懂 pycodestyle 模块:一个检查Python代码是否符合PEP8风格约定的工具,资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 pycodestyle 模块&#xff1a;一个检查Python代码是否符合PEP8风格约定的工具&#xff0c;资料整理笔记&#xff08;大全&#xff09; &#x1f9ca;摘要&#x1f9ca;模块…

chatgpt赋能python:Python中数字转换的完整指南

Python中数字转换的完整指南 转换数字是Python编程过程中经常需要的操作之一。Python提供了许多内置函数和库&#xff0c;可以方便地将数字转换为各种格式和数据类型。在本文中&#xff0c;我们将介绍Python中数字转换的完整指南&#xff0c;包括各种转换方法和最佳实践。 内…

chatgpt赋能Python-python_读取bin

介绍 Python 作为一种高级编程语言&#xff0c;已经被广泛地应用在各种领域&#xff0c;包括科学计算、人工智能、Web 开发等等。在这些领域中&#xff0c;二进制文件的处理是不可避免的。Python 也提供了一些库和工具&#xff0c;让我们可以方便地读取和处理二进制文件。本文…

ChatGPT与讯飞星火实测对比

文章目录 一、推理测试测试提示词1&#xff1a;假设树上有10只鸟&#xff0c;开枪打死1只&#xff0c;那么树上还有几只鸟?- 测试提示词2&#xff1a;一艘船10天可以渡过太平洋&#xff0c;请计算10艘船多少天可以渡过太平洋。测试提示词3&#xff1a;我爸妈结婚的时候为什么不…

vue-i18n安装配置使用示例,并介绍在模版文本、组件方法、js,f方法里的使用

vue-i18n是一个项目的国际化组件&#xff0c;可以切换多个语言版本,很多vue项目都是用这个插件来处理语言切换的。 基本操作 1&#xff0c;安装引用&#xff1a; $ npm install vue-i18n<script src"https://unpkg.com/vue/dist/vue.js"></script> &…

Radxa ROCK 5A 开箱 vs 树莓派

Rock5 Model A 是一款高性能的单板计算机&#xff0c;它采用了 RK3588S (8nm LP 制程&#xff09;处理器&#xff0c;具有 4 个高达 2.4GHz 的 ARM Cortex-A76 CPU 核心、4 个高达 1.8GHz 的 Cortex-A55 内核和 Mali-G610 MP4 GPU。更重要的是&#xff0c;它还有一个高达 6TOPS…

chatgpt赋能python:Python词频分析:为什么Python是数据科学家和工程师的首选?

Python 词频分析&#xff1a;为什么 Python 是数据科学家和工程师的首选&#xff1f; Python 是一种通用、开放源代码、高级编程语言&#xff0c;近年来一直是数据科学和工程领域中最受欢迎的编程语言之一。Python 强大的数据处理能力迅速成为行业的首选&#xff0c;但是仅靠这…

linux中和,|和||及分号(;)的用法

在linux中&#xff0c;我们经常会用到&和&&&#xff0c;|和||及分号(;)&#xff0c;但是好多人对其会混淆&#xff0c;不明白其中的意思&#xff0c;今天为大家讲解一下&和&&&#xff0c;|和||及分号(;)各自的说明和用法。 1.& & 表示程序…

Linux-0.11 boot目录head.s详解

Linux-0.11 boot目录head.s详解 模块简介 在head.s中&#xff0c;操作系统主要做了如下几件事&#xff1a; 重新设置中断描述符和全局描述符检查A20地址线是否开启检查数学协处理器初始化页表并开启分页跳转到main函数执行 过程详解 重新设置IDT和GDT 在setup.s中我们已经…

chatgpt赋能python:Python逆序排列:从入门到精通

Python 逆序排列&#xff1a;从入门到精通 Python 语言因其简单易学、性能高效、多平台支持等优点而备受青睐。而在 Python 中进行逆序排列操作是我们经常需要用到的一个功能&#xff0c;本篇文章将详细介绍 Python 中的逆序排列操作。 什么是逆序排列&#xff1f; 逆序排列…

chatgpt赋能python:Python行转列:如何高效地处理大数据集

Python行转列&#xff1a;如何高效地处理大数据集 Python是一种广泛使用的编程语言&#xff0c;最初用于Web开发&#xff0c;如今已成为专业开发、科学计算和数据分析等领域的一种首选语言。Python非常方便&#xff0c;尤其是在处理大数据集时。本文将介绍如何使用Python将行数…

Protobuf协议初级详解(python使用)从安装到序列化-反序列化

教程 一、前言二、效果三、教程1&#xff09;安装2&#xff09;使用1.创建.proto文件2.proto语法3.protoc.exe文件编译.proto语法文件4.序列化5.反序列化 四、借鉴 一、前言 Protobuf是一种轻便高效的结构化数据存储格式&#xff0c;可以用于结构化数据序列化&#xff0c;很适合…

chatgpt赋能python:Python随机抽取:提高数据样本代表性的利器

Python随机抽取&#xff1a;提高数据样本代表性的利器 在数据分析和机器学习领域&#xff0c;我们经常需要对数据进行随机抽样以获得更有代表性的数据集。而Python提供了很多方便易用的函数和库&#xff0c;使得数据抽样变得更加简单和高效。 random库&#xff1a;生成随机序…

chatgpt赋能python:Python随机选择数字

Python随机选择数字 如果你正在寻找一种简单的方法在Python中选择随机数字&#xff0c;那么你来对地方了&#xff01;在这篇文章里&#xff0c;我们将介绍Python的内置模块random和它的方法来选择随机数字。 什么是Python的Random模块&#xff1f; Python的random模块是一个…

chatgpt赋能python:Python中的随机选择:介绍和应用

Python中的随机选择&#xff1a;介绍和应用 Python是一种流行的编程语言&#xff0c;广泛应用于数据科学、人工智能和网络开发等领域。Python中有许多方便的功能和库&#xff0c;使得编程工作更加轻松和高效。其中一个重要的库是random模块&#xff0c;它可以用来生成随机数和…

横向移动-传递攻击SMB服务利用psexecsmbexec

win2012以上版本&#xff0c;关闭了wdigest 或者安装了 KB287199补丁。无法获取明文密码 总的来说就是win2012后无法获取明文密码 解决办法就是&#xff1a; 1.可以利用哈希hash传递&#xff08;pth&#xff0c;ptk等进行移动&#xff09; 2.利用其他服务协议&#xff08;S…

chatgpt赋能python:【Python实例教程】如何使用Python计算长方形面积

【Python实例教程】如何使用Python计算长方形面积 Python是一种广泛使用的高级编程语言&#xff0c;因其易学易用的特性而备受推崇。Python在编写程序时也可以很方便地进行数学计算。本篇文章将介绍如何使用Python计算长方形的面积&#xff0c;希望对Python初学者有所帮助。 …

访客管理系统:Lobby Track Crack

Lobbytrack桌面 for 微软视窗 一个强大的、功能齐全的现场访客管理系统解决方案。在本地管理您的数据&#xff0c;网络工作站一起配置访客管理流程的各个方面。 扩展您的系统将本地 Web 模块 添加到您的 Lobbytrack 桌面系统&#xff0c;并允许您的员工使用本地 Intranet 上的 …