Tagged pointer 一种能够提升性能、节省内存的技术

概念

在计算机领域中,tagged pointer 是一个指针(内存地址),这种指针关联着额外的数据信息,例如indirection bit(间接位)或者refrence count(引用技术),这些数据通常被“folded”到指针中。这些额外数据称作为“标签”,“标签”是用来指定类型。

应用

关于Tagged pointer应用在很多地方,这里主要谈论在Objective-C中的应用,如果想要有更多了解,可以参考WikipediA的Tagged pointer这篇文章。下面我们就来谈谈Tagged pointer技术在Objective-C中的应用:

在OS X 10.10中,Apple就开始使用Tagged pointer技术了,OC中的class points(类指针)是字对齐的,也就是说对象在内存中是对齐的,它们的地址总是指针大小的整数倍,通常是16的倍数,OC中对象指针是一个64位整数,如果指针的最低有效位为1(奇数),这个指针就是Tagged pointer,紧接着3位表示类表的索引,剩下的60位为类所用。Tagged pointer中的“标签”用于许多用途,例如:存储引用技术和是否含义析构函数。

Tagged pointer在OC中有一个简单的应用就是NSNumber,接下来我们来看看NSNumber是如何应用Tagged pointer:

下面是我在64位 Mac上Xcode 8.0的运行代码:

for (int i = 0; i < 11; i++) {
    NSNumber *num = [NSNumber numberWithInt:i];
    // 打印出地址
    NSLog(@"%p\n", num);
}
    
输出如下:
2016-10-30 15:13:36.073573 LearningOC-NSObject[39610:2880360] 0x27
2016-10-30 15:13:36.073605 LearningOC-NSObject[39610:2880360] 0x127
2016-10-30 15:13:36.073620 LearningOC-NSObject[39610:2880360] 0x227
2016-10-30 15:13:36.073722 LearningOC-NSObject[39610:2880360] 0x327
2016-10-30 15:13:36.073739 LearningOC-NSObject[39610:2880360] 0x427
2016-10-30 15:13:36.073755 LearningOC-NSObject[39610:2880360] 0x527
2016-10-30 15:13:36.073769 LearningOC-NSObject[39610:2880360] 0x627
2016-10-30 15:13:36.073782 LearningOC-NSObject[39610:2880360] 0x727
2016-10-30 15:13:36.073797 LearningOC-NSObject[39610:2880360] 0x827
2016-10-30 15:13:36.073812 LearningOC-NSObject[39610:2880360] 0x927
2016-10-30 15:13:36.073850 LearningOC-NSObject[39610:2880360] 0xa27

由输出可以看出num明显不是对象指针,而是Tagged pointer。理由很简单:因为在64位Mac地址空间的开头里,4GB零页是未映射且不可映射的,所以上面输出的地址明显很小,不可能是对象指针。

输出地址中,最后一位7用二进制表示为: 1001
最后一位1表示该指针为 Tagged pointer; 紧跟着三位100表示NSNumber这个类;倒数第二位2用二进制表示为0010,表示数据类型(int),这个也可以从以下实验看出:

NSNumber *floatNum = [NSNumber numberWithFloat:1];
NSLog(@"floatNum:%p\n", floatNum);
NSNumber *intNum = [NSNumber numberWithInt:1];
NSLog(@"intNum:%p\n", intNum);
NSNumber *longNum = [NSNumber numberWithLong:1];
NSLog(@"longNum:%p\n", longNum);
NSNumber *charNum = [NSNumber numberWithChar:1];
NSLog(@"charNum:%p\n", charNum);

输出如下:
2016-10-30 15:42:44.870889 LearningOC-NSObject[41617:2922729] floatNum:0x147
2016-10-30 15:42:44.870912 LearningOC-NSObject[41617:2922729] intNum:0x127
2016-10-30 15:42:44.870931 LearningOC-NSObject[41617:2922729] longNum:0x137
2016-10-30 15:42:44.870951 LearningOC-NSObject[41617:2922729] charNum:0x107

现在,有上述内容可以看出,64位的地址已经花费了8个位用来表示数据类型、类、指针类型了。留下56位来表示数值了。在int数据中,第一位是符号位,所以我们能表达的最大数值为2^55 - 1,当数值超过2^55 - 1则用NSNumber对象指针来存储,以下实验足以证明这个结论:

NSNumber *num1 = [NSNumber numberWithLong:((long)pow(2, 55)) - 1];
NSNumber *num2 = [NSNumber numberWithLong:((long)pow(2, 55))];
NSLog(@"num1:%p  numb2:%p\n", num1, num2);

输出如下:
2016-10-30 16:07:24.943873 LearningOC-NSObject[43567:2961854] num1:0x7fffffffffffff37  numb2:0x100200370

接下来我们来看看关于引用计数,现在我已经把Xcode环境配置为MRC,然后执行以下代码:

NSNumber *intNum = [NSNumber numberWithInt:1];
NSLog(@"retainCount:%lu", (unsigned long) intNum.retainCount);

输出如下:
2016-10-30 16:37:28.496776 LearningOC-NSObject[45654:3007376] retainCount:9223372036854775807

可以看出retainCount是一个巨大的数值,也就表示该对象该内存中不被释放,这样也省去了释放内存操作。

以上是apple使用Tagged pointer应用在NSNumber,下面我们来分析一下这样用的好处:
首先,当创建一个NSNumber对象时,使用Tagged pointer可剩下一个真正的对象内存的分配(因为数值是存在指针里,而不是指针所指向的内存里),其次在调用相应方法是,如doubleValue方法时,是直接取指针中高60位表示的数值,这样可以省下一次间接取值的时间。最后,由于引用计数可以是空指令,因为没有内存需要释放。这对于常用的类,性能也是巨大的提升!

总结

Tagged pointer确实是能够提升内存和性能的有趣的技术.当然,NSNumber只是一个简单的应用,吸引Apple官方对Tagged pointer应用花更多时间处理的当然是NSString(NSMutableString)字符串处理了。这里就不多描述了。感兴趣的可以去看看这篇文章:【译】采用Tagged Pointer的字符串

参考文献

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容

  • 在2013年9月,苹果推出了iPhone5s,配备了首个采用64位架构的A7双核处理器,为了节省内存和提高执行效率...
    Pandakingli阅读 5,400评论 4 14
  • 29.理解引用计数 Objective-C语言使用引用计数来管理内存,也就是说,每个对象都有个可以递增或递减的计数...
    Code_Ninja阅读 1,490评论 1 3
  • 在调试程序或者反编译App时,经常可以看到"NSTaggedPointerString"这个东西例如: 打印: 这...
    Mr_Baymax阅读 10,411评论 15 48
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,715评论 0 9
  • 一起走过,一起笑过,一起难受过 最后的离别,那一刻来临后,所有的所有 都化作烟,逝去了 看的太透,想的很清楚,理性...
    与君共度时艰阅读 176评论 0 1