博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
小码哥iOS学习笔记第二十四天: Tagged Pointer
阅读量:6259 次
发布时间:2019-06-22

本文共 2309 字,大约阅读时间需要 7 分钟。

一、iOS程序的内存布局

二、Tagged Pointer

  • 从64bit开始,iOS引入了Tagged Pointer技术,用于优化NSNumberNSDateNSString等小对象的存储
  • 在没有使用Tagged Pointer之前, NSNumber等对象需要动态分配内存、维护引用计数等,NSNumber指针存储的是堆中NSNumber对象的地址值
  • 使用Tagged Pointer之后,NSNumber指针里面存储的数据变成了: Tag + Data,也就是将数据直接存储在了指针中
  • 当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
NSNumber *num1 = [NSNumber numberWithInt:1];NSNumber *num2 = @(2);NSNumber *num3 = @3;NSNumber *num4 = @(1233221132133211233);NSLog(@"%p", num1);NSLog(@"%p", num2);NSLog(@"%p", num3);NSLog(@"%p", num4);复制代码

  • objc_msgSend能识别Tagged Pointer,比如NSNumberintValue方法,直接从指针提取数据,节省了以前的调用开销
NSNumber *num1 = [NSNumber numberWithInt:1];[num1 intValue];复制代码
  • 如何判断一个指针是否为Tagged Pointer
    • iOS平台,最高有效位是1(第64bit)
    • Mac平台,最低有效位是1

  • 判断一个指针是否是Tagged Pointer的源码使用的是_objc_isTaggedPointer函数
static inline bool _objc_isTaggedPointer(const void * _Nullable ptr) {    return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;}复制代码

三、面试题

1、下面这段代码执行后, 会发生什么

#import "ViewController.h"@interface ViewController ()@property (nonatomic, copy) NSString *name;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);    for (int i = 0; i < 1000; i++) {        dispatch_async(queue, ^{            self.name = [NSString stringWithFormat:@"abcdefghijklmn"];        });    }}@end复制代码
  • 运行程序, 可以看到崩溃在了objc_release

  • 这主要是因为在-setName:方法中, 实际的实现如下
- (void)setName:(NSString *)name{    if (_name != name) {        [_name release];        _name = [name copy];    }}复制代码
  • 因为使用多线程赋值, 所以会有多个线程同时调用[_name release], 所以才发触发上面的崩溃
  • 解决的方式就是加锁, 可以使用atomic, 或者其他的锁
@property (atomic, copy) NSString *name;复制代码

2、下面的代码为什么可以正常运行, 不会崩溃

#import "ViewController.h"@interface ViewController ()@property (nonatomic, copy) NSString *name;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    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"];        });    }}@end复制代码
  • 运行程序, 上面的代码确实不会发生崩溃
  • 这是因为[NSString stringWithFormat:@"abc"]是一个Tagged Pointer, 在调用-setName:方法时, 底层使用的是objc_msgSend(self, @selector(setName:)
  • 此时就会在底层调用_objc_isTaggedPointer函数判断是否是Tagged Pointer, 如果是, 就会直接将地址赋值给_name, 没有releasecopy的操作

转载于:https://juejin.im/post/5c931b59e51d45733067e6b9

你可能感兴趣的文章
css3--之backface-visibility
查看>>
软件需求分析之猫咪记单词
查看>>
good vs evil
查看>>
算法28-----范围求和
查看>>
基于V4L2的视频驱动开发(1)
查看>>
zoj 1008
查看>>
VC++ CArchive及简单的文件操作方法
查看>>
使用canvas制作一个移动端画板
查看>>
android中ListView数据混乱问题
查看>>
QT学习-10/31/2012
查看>>
jQuery File Upload
查看>>
bbb板运行rtems-编写led底层驱动
查看>>
如何从零安装Mysql
查看>>
Appium简介及工作原理
查看>>
IP 类型转换
查看>>
mysql实践1
查看>>
struts2 Preparable接口
查看>>
hdu4578(线段树)
查看>>
写一个脚本简单检测局域网存活的机器
查看>>
Dubbo
查看>>