iOS中 Tagged Pointer 技术
前言:
从64位开始,iOS引入了Tagged Pointer技术,用于优化NSNumber、NSDate、NSString等小对象的存储。
Tagged Pointer主要为了解决两个问题:
- 内存资源浪费,堆区需要额外的开辟空间
- 访问效率,每次set/get都需要访问堆区,浪费时间, 而且需要管理堆区对象的声明周期,降低效率
Tagged Pointer特点:
- 专门用来存储小对象,比如NSString,NSNumber,NSDate
Tagged Pointer指针的值不再是堆区地址,而是包含真正的值。所以它不会在堆上再开辟空间了,也不需要管理对象的生命周期了。- 内存读取提升
3倍,创建比之前快100多倍,销毁速度更快
一、引入Tagged Pointer 前后对比

1、引入前
NSNumber等对象需要动态分配内存、维护引用计数等。 总共的空间= 指针空间 + 堆中分配的空间
2、引入后
NSNumber等对象,只需要分配一个指针即可,这个指针内部会包含这些数据内容。
总空间 = 指针空间
因为不用去用对象的方式管理引用计数,所以省却了 retain,release操作。
二、Tagged Pointer 原理
number1只有栈上的指针内存;而maxNum不仅有指针内存,在堆中还分配了32字节的内存用于存储该变量的值。通过观察发现,对象的number1、number2、number3、number4都存储在了对应的指针中;而maxNum不同由于数据过大,导致无法 1 个指针 8 个字节的内存根本存不下,而申请了32字节堆内存。
NSString类型的Tagged Pointer指针与基本类型的指针是不一样的,末尾的数字为字符串的长度;NSString类型的Tagged Pointer指针存储char类型,返回的是ASCII码(该值为16进制的,需要进行十进制转换)
三、如何判断是否使用了 Tagged Pointer 技术
BOOL isTaggedPointer(id pointer) {
return (long)(__bridge void *)pointer & 1;
}
该函数就是调用了isTaggedPointer。
四、使用 Tagged Pointer 注意点
我们知道,所有OC对象都有isa指针,而Tagged Pointer并不是真正的对象,它没有isa指针,所以如果你直接访问Tagged Pointer的isa成员的话,在编译时将会有警告。
五、面试题
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i<1000; i++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"abcdefghijk"];
});
}
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i<1000; i++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"abc"];
});
}
两者运行结果有何不同?
首先看self.name = [NSString stringWithFormat:@"abcdefghijk"];

崩溃,并且崩溃在objc_release的地方。
是什么原因导致崩溃的呢?
我们知道,
self.name = [NSString stringWithFormat:@"abcdefghijk"];
其实是调用了
[self setName:[NSString stringWithFormat:@"abcdefghijk"]];
而setName:的实现是:
- (void)setName:(NSString *)name
{
if (_name != name) {
[_name release];//老的释放掉
_name = [name copy];//传入的值copy后赋值给_name
}
}
由于是async异步操作,self.name = [NSString stringWithFormat:@"abcdefghijk"];即[_name release];有可能会被多条线程同时操作。导致,线程n把_name释放掉,线程n+1又要执行_name的释放,从而造成_name已经被释放两次,第二次访问的时候,_name已经释放过,造成坏内存访问。
解决方法一:atomic
@property (copy, atomic) NSString *name;
从而:
- (void)setName:(NSString *)name
{
//加锁操作
if (_name != name) {
[_name release];
_name = [name copy];
}
//解锁操作
}
解决方法二:
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i<1000; i++) {
dispatch_async(queue, ^{
//加锁
self.name = [NSString stringWithFormat:@"abcdefghijk"];
});
//解锁
}
self.name = [NSString stringWithFormat:@"abc"];
为何没有崩溃呢?


从类型可以看出来,
内容多的name类型是__NSCFString
内容少的name类型是NSTaggedPointerString

这就是原因所在。
内容少的name,由于类型是NSTaggedPointerString,在赋值的时候
是直接在指针里面取值,而不需要release操作,因此,不会崩溃
iOS中 Tagged Pointer 技术的更多相关文章
- OS X 和iOS 中的多线程技术(上)
OS X 和iOS 中的多线程技术(上) 本文梳理了OS X 和iOS 系统中提供的多线程技术.并且对这些技术的使用给出了一些实用的建议. 多线程的目的:通过并发执行提高 CPU 的使用效率,进而提供 ...
- OS X 和iOS 中的多线程技术(下)
OS X 和iOS 中的多线程技术(下) 上篇文章中介绍了 pthread 和 NSThread 两种多线程的方式,本文将继续介绍 GCD 和 NSOperation 这两种方式.. 1.GCD 1. ...
- iOS中 动态热修补技术JSPatch 韩俊强的博客
.1.4) JSPatch bridge Objective-C and JavaScript. You can call any Objective-C class and method in Ja ...
- iOS中 图文混排/自定义图文混排 作者:韩俊强
指示根视图:(准备几张图片,把label加载在window上) CustomLable *label = [[CustomLable alloc]initWithFrame:CGRectMake(0, ...
- iOS中常用的四种数据持久化技术
iOS中的数据持久化方式,基本上有以下四种:属性列表 对象归档 SQLite3和Core Data 1.属性列表涉及到的主要类:NSUserDefaults,一般 [NSUserDefaults st ...
- Tagged Pointer
前言 在2013年9月,苹果推出了iPhone5s,与此同时,iPhone5s配备了首个采用64位架构的A7双核处理器,为了节省内存和提高执行效率,苹果提出了Tagged Pointer的概念.对于6 ...
- 从一道网易面试题浅谈 Tagged Pointer - darcy_tang 的博客
前言 这篇博客九月就想写了,因为赶项目拖了到现在,抓住17年尾巴写吧~ 正文 上次看了一篇 <从一道网易面试题浅谈OC线程安全> 的博客,主要内容是: 作者去网易面试,面试官出了一道面试题 ...
- iOS 中的 HotFix 方案总结详解
相信HotFix大家应该都很熟悉了,今天主要对于最近调研的一些方案做一些总结.iOS中的HotFix方案大致可以分为四种: WaxPatch(Alibaba) Dynamic Framework(Ap ...
- ios中@class和 #import区别
很多刚开始学习iOS开发的同学可能在看别人的代码的时候会发现有部分#import操作写在m文件中,而h文件仅仅使用@class进行声明,不禁纳闷起来,为什么不直接把#import放到h文件中呢?这是因 ...
随机推荐
- Android添加背景图片和设置app图标
Android添加背景图片和设置app图标 Android 添加背景图片 第一步:找到你要当做背景的图片,并下载下来 第二步:将图片复制到app->res->mipmap文件夹下 第三步: ...
- CentOS7安装部署Mongodb
1.下载安装包 打开官网,跳转至下载界面,选择对应版本的安装包,拷贝其链接,这里是手动安装,所以下载tgz安装包,如果要自动化安装,选择server的rpm自动安装包 https://www.mong ...
- JWT 访问令牌
JWT 访问令牌 更为详细的介绍jwt 在学习jwt之前我们首先了解一下用户身份验证 1 单一服务器认证模式 一般过程如下: 用户向服务器发送用户名和密码. 验证服务器后,相关数据(如用户名,用户角色 ...
- Nexus5x 修改Android开机动画
1.制作帧动画 这里随便从网上找了一个gif图片,导入PS中,打开后会形成很多帧图层,选择导航栏中的文件->脚本->将图层导出到文件可以将所有图层导出来.要注意文件命名,Android会按 ...
- Java类包
学习内容:Java类包 一.Java类包 1.一个完整的类名需要包名和类名的组合,每一个类都隶属于一个包. 例:完整类名--java.sql.Date 2.同一个包中类相互访问时可以不指明包名. 3. ...
- 解决Docker运行命令时提示"Got permission denied while trying to connect to the Docker daemon socket"类情况
Docker安装命令: 解决Docker运行命令时提示"Got permission denied while trying to connect to the Docker daemon ...
- 高性能 Jsonpath 框架,Snack3 3.2.29 发布
Snack3,一个高性能的 JsonPath 框架 借鉴了 Javascript 所有变量由 var 申明,及 Xml dom 一切都是 Node 的设计.其下一切数据都以ONode表示,ONode也 ...
- 老子云AMRT全新三维格式正式上线,其性能全面超越现有的三维数据格式
9月16日,老子云AMRT全新三维格式正式上线,其性能远超现有的三维数据格式.目前已有含国家超算长沙中心.中科院空间所.中车集团等上百家政企事业单位的项目中使用了AMRT格式,大大提升了可视化项目的开 ...
- Win 系统下使用gnvm操作node版本
下载 gnvm官方网址 有好几种安装方式,我这里使用的是百度网盘下载. 安装 下载完成将gnvm.exe文件放到node的安装根目录下,如果你不知道安装目录在哪?可以使用命令: where node ...
- VueX的模块你知道多少?
为什么会出现VueX的模块呢?当你的项目中代码变多的时候,很难区分维护.那么这时候Vuex的模块功能就这么体现出来了. 那么我们就开始吧!一.模块是啥? /* eslint-disable no-un ...