前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OC底层探索27-TaggedPointOC底层探索27-TaggedPoint

OC底层探索27-TaggedPointOC底层探索27-TaggedPoint

作者头像
用户8893176
发布2021-08-09 11:12:10
4470
发布2021-08-09 11:12:10
举报
文章被收录于专栏:小黑娃Henry

在objc的源码分析中,经常看到这个isTaggedPointer判断,这个TaggedPoint有什么特别呢?

1、 TaggedPointer简介

taggedPonint

  • Tagged Pointer专门用来存储小的对象,例如NSNumber, NSDate, NSString。
  • Tagged Pointer指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc和free。(在常量区)
  • 在内存读取上有着3倍的效率,创建时比以前快106倍。
1.1 TaggedPointer标示
代码语言:javascript
复制
#if OBJC_MSB_TAGGED_POINTERS
#   define _OBJC_TAG_MASK (1UL<<63)
#else
#   define _OBJC_TAG_MASK 1UL
#endif

static inline bool 
_objc_isTaggedPointer(const void * _Nullable ptr)
{
    return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
  • 我们都知道一个对象地址为64位二进制,它表明如果64位数据中,最高位是1的话,则表明当前是一个tagged pointer类型
1.2 对象的加密&解密
代码语言:javascript
复制
static inline void * _Nonnull
_objc_encodeTaggedPointer(uintptr_t ptr)
{
    uintptr_t value = (objc_debug_taggedpointer_obfuscator ^ ptr);
    return (void *)value;
}

static inline uintptr_t
_objc_decodeTaggedPointer_noPermute(const void * _Nullable ptr)
{
    uintptr_t value = (uintptr_t)ptr;
    return value ^ objc_debug_taggedpointer_obfuscator;
}
  • objc_debug_taggedpointer_obfuscator这个值苹果源码中并没用开源;但不影响我们理解;
  • 操作例如: 1010 ^ 1111 = 0101 (encode) 0101 ^ 1111 = 1010 (decode)
1.3 对象类型

objc4-750之前:

objc4-750之后,对象类型获取变得复杂起来了。

代码语言:javascript
复制
// Returns a pointer to the class's storage in the tagged class arrays.
// Assumes the tag is a valid basic tag.
static Class *
classSlotForBasicTagIndex(objc_tag_index_t tag)
{
    uintptr_t tagObfuscator = ((objc_debug_taggedpointer_obfuscator
                                >> _OBJC_TAG_INDEX_SHIFT)
                               & _OBJC_TAG_INDEX_MASK);
    uintptr_t obfuscatedTag = tag ^ tagObfuscator;
    // Array index in objc_tag_classes includes the tagged bit itself
#if SUPPORT_MSB_TAGGED_POINTERS ////高位优先
    return &objc_tag_classes[0x8 | obfuscatedTag];
#else
    return &objc_tag_classes[(obfuscatedTag << 1) | 1];
#endif
}
  • classSlotForBasicTagIndex() 函数的主要功能就是根据指定索引 tag 从数组objc_tag_classes中获取类指针,而下标的计算方法发是根据外部传递的索引tag。比如字符串 tag = 2。当然这并不是简单的从数组中获取某条数据。

进一步了解这部分的操作,可参考内存管理之Tagged pointer

1.4 对象的值
代码语言:javascript
复制
static inline uintptr_t
_objc_getTaggedPointerValue(const void * _Nullable ptr) 
{
    // ASSERT(_objc_isTaggedPointer(ptr));
    uintptr_t value = _objc_decodeTaggedPointer_noPermute(ptr);
    uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
    if (basicTag == _OBJC_TAG_INDEX_MASK) {
        return (value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
    } else {
        return (value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
    }
}

static inline uintptr_t
_objc_decodeTaggedPointer_noPermute(const void * _Nullable ptr)
{
    uintptr_t value = (uintptr_t)ptr;
#if OBJC_SPLIT_TAGGED_POINTERS
    if ((value & _OBJC_TAG_NO_OBFUSCATION_MASK) == _OBJC_TAG_NO_OBFUSCATION_MASK)
        return value;
#endif
    return value ^ objc_debug_taggedpointer_obfuscator;
}

测试:

代码语言:javascript
复制
NSString *str1 = [NSString stringWithFormat:@"1"];
NSString *str11 = [NSString stringWithFormat:@"11"];

uintptr_t value1 = _objc_getTaggedPointerValue((__bridge void *)str1);
uintptr_t value2 = _objc_getTaggedPointerValue((__bridge void *)str2);

输出:

代码语言:javascript
复制
TaggedPointer[89535:3033433] 311
TaggedPointer[89535:3033433] 31312

即 "1" = 0x31 在ASCII码表中31表示的就是字符1; 最后一位:“1”,"2" ,代表是字符串长度;

总结

TaggedPoint对象是一个特殊的对象,不会涉及到引用计数retainrelease等内存操作。对象的值就存在8位指针中,不过值通过了一份加密。


参考 内存管理之Tagged pointer

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/7/12 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、 TaggedPointer简介
    • 1.1 TaggedPointer标示
      • 1.2 对象的加密&解密
        • 1.3 对象类型
          • 1.4 对象的值
            • 总结
            相关产品与服务
            对象存储
            对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档