Objective-C Tagged Pointer
Tagged Pointer
在计算机科学领域,一个指针或地址空间,除了存放对象地址之外,也可以存放其他额外的信息,并将其中的一些bit位作为tag标记区分,这个就叫tagged pointer。
具体到Objective-C,一个指针(地址)需要用64位也就是16-byte的内存空间来存储,但实际上往往用不到全部,只用到了中间的部分,高位16-bit用不到,由于内存按字节对齐的要求,所以低位值也总是为0:
正常情况下,内存中对象和指针的关系是:一个指针的值存放的是一个地址,地址表示另一块内存区域,对象本身存放在那块内存区域中,这边需要的内存空间=对象占用的空间 指针占用的内存空间。
那么如果一个对象本身所需要的空间很小,少于一个指针所需要的空间,这样存放不就造成了不必要的内存浪费了吗,因此,可以将一些内存占用不大的对象(比如NSNumber、NSString、NSDate等)直接存到这个指针的内存空间中,这样就不需要再额外开辟一个空间来存放它,需要的内存空间=对象占用的空间,显著的节省了内存空间。
为了区分这个pointer是只用于存放地址的普通的pointer还是存放了其他信息的pointer,就选取其中的某个或某些位作为标记tag,剩下的位就可以用于存放所需要的数据,叫做payload,这样的指针就是tagged pointer。Objective-C runtime中,isa指针就是使用了tagged pointer来优化了内存。
在”objc-object.h”中,提供了内部接口判断是否是tagged pointer
inline bool
objc_object::isTaggedPointer()
Tagged Pointer的Tag和Payload
一个tagged pointer中,有一位作为mask用来标识是否是tagged pointer,接着是3位存放tag信息,tag可以取值0-7,如果值是0-6,表示它是一个basic tagged pointer, 而7作为保留值,表示是它是extended tagged pointer
basic tagged pointer中除了1位用于标识是否是tagged pointer,接下来3位存放对象类型的索引值,剩余60位是payload,用于存放想要存放的数据,比如对象的值。
extended tagged pointer中有1位mask和3位tag都取值1,用于表示是extended tagged pointer,接下来8位存放类型索引值,剩余52位作为payload存放数据。这样可以存放多达256种类型,代价是payload从60位减少到52位,能存放的数据减少了。
“objc-internal.h”中定义了tagged pointer对象类型的枚举:
enum objc_tag_index_t : uint16_t
{
// 60-bit payloads
OBJC_TAG_NSAtom = 0,
OBJC_TAG_1 = 1,
OBJC_TAG_NSString = 2,
OBJC_TAG_NSNumber = 3,
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSManagedObjectID = 5,
OBJC_TAG_NSDate = 6,
// 60-bit reserved
OBJC_TAG_RESERVED_7 = 7,
// 52-bit payloads
OBJC_TAG_Photos_1 = 8,
OBJC_TAG_Photos_2 = 9,
OBJC_TAG_Photos_3 = 10,
OBJC_TAG_Photos_4 = 11,
OBJC_TAG_XPC_1 = 12,
OBJC_TAG_XPC_2 = 13,
OBJC_TAG_XPC_3 = 14,
OBJC_TAG_XPC_4 = 15,
OBJC_TAG_First60BitPayload = 0,
OBJC_TAG_Last60BitPayload = 6,
OBJC_TAG_First52BitPayload = 8,
OBJC_TAG_Last52BitPayload = 263,
OBJC_TAG_RESERVED_264 = 264
};
具体哪些位存放tag和类型索引?
x86_64架构中,是基于LSB最低有效位,存放在低位:
Arm架构中,是基于MSB最高有效位,存放在高位: 为什么ARM上是高位表示,这边涉及到了msgSend的一项优化,放在高位可以使msgSend节省一个判断分支。
但是,iOS14后(WWDC2020中介绍),ARM平台上tag信息存放位做了一些调整,优化了读取二进制文件中的常量数据的内存消耗。具体来说,将3位tag放到了低位,同样的如果tag位位7,也是extended tagged pointer,扩展信息放在紧接着mask位后8位:
One more thing...
runtime中tagged pointer是被混淆过的,直接读取pointer内部的位得不到正确的信息的,tagged pointer内部实现的具体代码可以查看”objc-internal.h”
// 用于混淆tagged pointer的因子,会被初始化为一个随机数
extern uintptr_t objc_debug_taggedpointer_obfuscator;
static inline void * _Nonnull
_objc_encodeTaggedPointer(uintptr_t ptr);
static inline uintptr_t
_objc_decodeTaggedPointer(const void * _Nullable ptr);
static inline bool
_objc_taggedPointersEnabled(void);
static inline void * _Nonnull
_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value);
static inline bool
_objc_isTaggedPointer(const void * _Nullable ptr);
static inline objc_tag_index_t
_objc_getTaggedPointerTag(const void * _Nullable ptr);
static inline uintptr_t
_objc_getTaggedPointerValue(const void * _Nullable ptr);
static inline intptr_t
_objc_getTaggedPointerSignedValue(const void * _Nullable ptr);
总结:
- Tagged pointer不是一个正常的指针,是对指针内存空间的最大化利用,使用其中的一些bit位来和普通指针进行区分,剩余的位存放数据
- runtime中利用tagged pointer技术存放一些占用较小的对象,显著的优化了内存
- runtime中对tagged pointer做了混淆,提升了安全性
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhbafifg
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13