【iOS】—— Tagged Pointer
【iOS】—— Tagged Pointer
- 关于Tagged Pointer
- Tagged Pointer的介绍
- NSTaggedPointer示例
- NSTaggedPointer结构
- Tagged Pointer的特点
- 注意事项
- isa指针
- isa指针的优化
关于Tagged Pointer
为了节省内存和提高执行效率,苹果提出了Tagged Pointer的概念。先看看原有的对象为什么会浪费内存。假设要存储一个NSNumber对象,其值是一个整数。正常情况下,如果这个整数只是一个NSInteger的普通变量,那么它所占用的内存是与CPU的位数有关,在32位CPU下占4个字节,在64位CPU下是占8个字节的。而指针类型的大小通常也是与CPU位数相关,一个指针所占用的内存在32位CPU下为4个字节,在64位CPU下也是8个字节。所以一个普通的iOS程序,如果没有Tagged Pointer对象,从32位机器迁移到64位机器中后,虽然逻辑没有任何变化,但这种NSNumber、NSDate一类的对象所占用的内存会翻倍。
Tagged Pointer的介绍
为了存储和访问一个NSNumber对象,我们需要在堆上为其分配内存,另外还要维护它的引用计数,管理它的生命期。这些都给程序增加了额外的逻辑,造成运行效率上的损失。
对此提出了Tagged Pointer概念,由于NSNumber、NSDate一类的变量本身的值需要占用的内存大小常常不需要8个字节,拿整数来说,4个字节所能表示的有符号整数就可以达到20多亿。所以我们可以将一个对象的指针拆成两部分,一部分直接保存数据,另一部分作为特殊标记,表示这是一个特别的指针,不指向任何一个地址。
简单来理解就是把指针指向的内容,直接放到了指针变量的内存地址中。 于是使用了标签指针这种方式来优化数据的存储方式。在运行时根据实际情况创建。
NSTaggedPointer示例
NSString *string = nil; NSMutableString *mutableString = [NSMutableString stringWithFormat:@"abcde"]; for (int i = 0; i
输出结果:
当字符长度在10以内的时候,字符串的类型都是NSTaggedPointer类型,当超过10时,就变成了__NSCFString。
NSTaggedPointer结构
苹果为了安全对其做了编码,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




