iOS源码阅读必备知识之Tagged Pointer

Tagged Pointer 介绍

苹果对于Tagged Pointer特点的介绍:

  • Tagged Pointer专门用来存储小的对象,例如NSNumber和NSDate
  • Tagged Pointer指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc和free。
  • 在内存读取上有着3倍的效率,创建时比以前快106倍。

为什么要引入Tagged Pointer

iPhone5s 采用64位处理器。对于64位程序,我们的数据类型的长度是跟CPU的长度有关的。

这样就导致了 一些对象占用的内存会翻倍。

同时 维护程序中的对象需要 分配内存,维护引用计数,管理生命周期,使用对象给程序的运行增加了负担。

Tagged Pointer

为了改进上面提到的内存占用和效率问题,苹果提出了Tagged Pointer对象。由于NSNumber、NSDate一类的变量本身的值需要占用的内存大小常常不需要8个字节,拿整数来说,4个字节所能表示的有符号整数就可以达到20多亿(注:2^31=2147483648,另外1位作为符号位),对于绝大多数情况都是可以处理的。

我们可以将一个对象的指针拆成两部分,一部分直接保存数据,另一部分作为特殊标记,表示这是一个特别的指针,不指向任何一个地址。所以,引入了Tagged Pointer对象之后,64位CPU下NSNumber的内存图变成了以下这样:

Tagged Pointer

测试

#import 

int main(int argc, const char * argv[]) {
 @autoreleasepool {
 // insert code here...
 NSNumber *number1 = @1;
 NSNumber *number2 = @2;
 NSNumber *number3 = @3;
 NSNumber *numberFFFF = @(0xFFFF);

 NSNumber *numberLager = @(MAXFLOAT);

 NSLog(@"number1 pointer is %p", number1);
 NSLog(@"number2 pointer is %p", number2);
 NSLog(@"number3 pointer is %p", number3);
 NSLog(@"numberLager pointer is %p", numberLager);

 /*
 2017-03-10 12:07:50.731726 TaggedPoint[1690:50438] number1 pointer is 0x127
 2017-03-10 12:07:50.731992 TaggedPoint[1690:50438] number2 pointer is 0x227
 2017-03-10 12:07:50.732011 TaggedPoint[1690:50438] number3 pointer is 0x327
 2017-03-10 12:07:50.732043 TaggedPoint[1690:50438] numberLager pointer is 0x1002006a0
 */

 }
 return 0;
}

以 0x127 为例 去掉 tag27(假设27为标记) 0x1 就是number 的值。

0x227

0x327

都有这种规律

numberLager 存储的值为MAXFloat 显然超过了tagged pointer 可以存储的范围。

所以打印的地址是单纯的指针地址,指向存储numberLager的内存地址。

对于isa指针的影响

因为tagged pointer 不是一个真正的对象,如果使用isa指针在编译时会报错。

如图:

提示我们改为object_getClass()

object_getClass()中做了相应的处理

由于object_getClass()没有对应的实现,只能从其他地方窥探一二

objc-weak.mm

weak_read_no_lock(weak_table_t *weak_table, id *referrer_id)
{
 objc_object **referrer = (objc_object **)referrer_id;
 objc_object *referent = *referrer;
 if (referent->isTaggedPointer()) return (id)referent;
 //...
}
inline bool
objc_object::isTaggedPointer()
{
#if SUPPORT_TAGGED_POINTERS
 return ((uintptr_t)this & TAG_MASK);
#else
 return false;
#endif
}

这里取对象的值做了一些判断

如果是tagged pointer , 对象的值就是指针

如果非tagged pointer , 对象的值是指针指向的内存区域中的值

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • iOS源码阅读必备知识之Tagged Pointer

    Tagged Pointer 介绍 苹果对于Tagged Pointer特点的介绍: Tagged Pointer专门用来存储小的对象,例如NSNumber和NSDate Tagged Pointer指针的值不再是地址了,而是真正的值.所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已.所以,它的内存并不存储在堆中,也不需要malloc和free. 在内存读取上有着3倍的效率,创建时比以前快106倍. 为什么要引入Tagged Pointer iPhone5s 采用64位处理器.

  • vue-next/runtime-core 源码阅读指南详解

    写在前面 最近又抽时间把 vue-next/runtime-core 的源码陆陆续续地看完了,期间整理了很多笔记,但都是碎片化的.本来是想整理一下,写成一篇文章分享出来的,但是感觉最终的成果物只能是一篇篇幅巨长的解析文,就算我一行一行的把源码加上注释,其阅读体验也会很差,因为每个人读代码的习惯不同,思路不同.正所谓抛砖引玉,所以,我觉的写一篇向导文作为这块砖应该是足够了,希望可以帮助到想看源码但觉得无从看起.无从下手的读者. 另一方面,也算是给自己挖一个坑,因为这篇文章中涉及到的很多内容,三言两

  • Nacos源码阅读方法

    为什么我会经常阅读源码呢,因为阅读源码能让你更加接近大佬,哈哈,这是我瞎扯的. 这篇文章将会带大家阅读Nacos源码 以及 教大家阅读源码的技巧,我们正式开始吧! 先给大家献上一张我梳理的高清源码图,方便大家对nacos的源码有一个整体上的认识. 有了这张图,我们就很容易去看nacos源码了. 如何找切入点 首先我们得要找一个切入点进入到nacos源码中,那么就从nacos依赖入手 <dependency> <groupId>com.alibaba.cloud</groupI

  • CloudStack SSVM启动条件源码阅读与问题解决方法

    CloudStack SSVM启动条件源码阅读与问题解决方法: 在CloudStack建立zone的时候,经常遇到SSVM不启动,或者根本就没有SSVM的情况,分析CloudStack日志,会发现有"Zone 1 is not ready to launch secondary storage VM yet"打印,意思是zone还未准备好启动SSVM. 通过查询CloudStack源代码,发现启动SSVM前有如下检查:         获取Zone里的template. select

  • Three.js源码阅读笔记(Object3D类)

    这是Three.js源码阅读笔记的第二篇,直接开始. Core::Object3D Object3D似乎是Three.js框架中最重要的类,相当一部分其他的类都是继承自Object3D类,比如场景类.几何形体类.相机类.光照类等等:他们都是3D空间中的对象,所以称为Object3D类.Object3D构造函数如下: 复制代码 代码如下: THREE.Object3D = function () { THREE.Object3DLibrary.push( this ); this.id = THR

  • Three.js源码阅读笔记(物体是如何组织的)

    这是Three.js源码阅读笔记第三篇.之前两篇主要是关于核心对象的,这些核心对象主要围绕着矢量vector3对象和矩阵matrix4对象展开的,关注的是空间中的单个顶点的位置和变化.这一篇将主要讨论Three.js中的物体是如何组织的:即如何将顶点.表面.材质组合成为一个具体的对象. Object::Mesh 该构造函数构造了一个空间中的物体.之所以叫"网格"是因为,实际上具有体积的物体基本都是建模成为"网格"的. 复制代码 代码如下: THREE.Mesh =

  • 源码阅读之storm操作zookeeper-cluster.clj

    storm操作zookeeper的主要函数都定义在命名空间backtype.storm.cluster中(即cluster.clj文件中). backtype.storm.cluster定义了两个重要protocol:ClusterState和StormClusterState. clojure中的protocol可以看成java中的接口,封装了一组方法.ClusterState协议中封装了一组与zookeeper进行交互的基础函数,如获取子节点函数,获取子节点数据函数等,ClusterStat

  • Java终止线程实例和stop()方法源码阅读

    了解线程 概念 线程 是程序中的执行线程.Java 虚拟机允许应用程序并发地运行多个执行线程. 线程特点 拥有状态,表示线程的状态,同一时刻中,JVM中的某个线程只有一种状态; ·NEW 尚未启动的线程(程序运行开始至今一次未启动的线程) ·RUNNABLE 可运行的线程,正在JVM中运行,但它可能在等待其他资源,如CPU. ·BLOCKED 阻塞的线程,等待某个锁允许它继续运行 ·WAITING 无限等待(再次运行依赖于让它进入该状态的线程执行某个特定操作) ·TIMED_WAITING 定时

  • jdk源码阅读Collection详解

    见过一句夸张的话,叫做"没有阅读过jdk源码的人不算学过java".从今天起开始精读源码.而适合精读的源码无非就是java.io,.util和.lang包下的类. 面试题中对于集合的考察还是比较多的,所以我就先从集合的源码开始看起. (一)首先是Collection接口. Collection是所有collection类的根接口;Collection继承了Iterable,即所有的Collection中的类都能使用foreach方法. /** * Collection是所有collec

  • Integer IntegerCache源码阅读

    先看一段测试结果: /*public static void main(String[] args) { Integer a = 128, b = 128; Integer c = 127, d = 127; System.out.println(a == b);//false System.out.println(c == d);//true }*/ /*public static void main(String[] args) { Integer int1 = Integer.valueO

随机推荐