iOS特有概念TaggedPointer
前言
近段时间一直在抽时间复习整理OC相关基础知识,在验证copy相关特性时创建字符串时偶然发现其中包含一种之前没有注意过的中间类型(NSTaggedPointerString)。今天有时间整理下相关内容记录如下:
1、关于TaggedPointer
2013年9月苹果推出了首个采用64位架构的A7双核处理器的手机iPhone5s,为了改进从32位CPU迁移到64位CPU的内存浪费和效率问题,在64位CPU环境下,苹果工程师提出了Tagged Pointer的概念。采用这一机制,系统会对NSString、NSNumber和NSDate等对象进行优化。
众所周知一般的 iOS 程序,从32位迁移到64位CPU,逻辑上虽然不会有任何变化,但是所占有的内存空间却会翻倍。下面以NSNumber对象为例,大家可以清晰看出NSNumber对象在内存空间上的变化情况:
引入TaggedPointer特性--NSNumber对象内存分布影响2、TaggedPointer特性分析
网络上可以查到很多利用NSString对象来分析TaggedPointer的技术贴,但是笔者复现时结果并不一致,根据打印出来的信息也不能分析出有什么特殊的地方。没有办法只能翻出万能的runtime源码,果然在里面发现了相关内容:
编码/解码函数可以看到,系统对TaggedPointer进行了混淆操作,主要就是将value与一个定义的全局变量objc_debug_taggedpointer_obfuscator进行异或操作,读取value时同样通过与objc_debug_taggedpointer_obfuscator进行异或操作来还原初始值。
但为什么笔者复现的结果与网络上很多技术贴不一致呢,我们接着看可以发现在Mac10.14和iOS12之前,对value做异或操作的objc_debug_taggedpointer_obfuscator值为0,之后为objc_debug_taggedpointer_obfuscator &= ~_OBJC_TAG_MASK,这也就解释了复现情况为什么不一致了。
初始化混淆器数值看到这里相信大家也知道了我们只要将结果进行解码操作就可以了,具体我们可以重新申明objc_debug_taggedpointer_obfuscator(全局变量)并且重写_objc_decodeTaggedPointer解码方法(内联函数)。具体可以可以参考如下:
接着我们借助NSString属性来对TaggedPointer进行具体分析,这里笔者就不一一叙述NSTaggedPointerString的具体存储规则了,网络上有很多相关内容,大家可以自行查找。
同时笔者逐步断点并在控制台进行po打印时发现一些特殊情况(NSTaggedPointerString类型的字符串不存在isa指针),这个打印结果足以说明NSTaggedPointerString是一个特别的指针,且不指向任何一个地址。因为我们都知道一个事实--所有对象都有 isa 指针,但NSTaggedPointerString是没有的,所以我们可以得出结论NSTaggedPointerString不是真正的对象。 如果直接访问Tagged Pointer的isa成员的话,将会有警告打印出来。
结论
1、Tagged Pointer有长度限制,过长会依然会采用对象的形式保存
2、Tagged Pointer没有isa指针,它不是一个对象,只是一个伪装成对象的普通变量而已。
3、Tagged Pointer是一个特殊的指针,不指向任何实质地址。