@property (nonatomic, copy) NSString *test;
复制代码
for (int i = 0; i < 1000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.test = [NSString stringWithFormat:@"%@",@"123"];
});
}
复制代码
for (int i = 0; i < 1000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.test = [NSString stringWithFormat:@"%@",@"abababababababababababababab"];
});
}
复制代码
运行段代码 有什么区别? 现象是什么?安全
查看崩溃日志多线程
test属性 setter方法实际执行如下内容async
- (void)setTest:(NSString *)test {
if (![_test isEqualToString:test]) {
[_test release];
_test = [test copy];
[test release];
}
}
复制代码
因为test 修饰为nonatomic 因此是线程不安全的。 当多条线程同时访问,形成屡次release ,因此坏内存访问。优化
修饰改成atomic 或者加锁ui
首先打印两个NSString的类型this
正常对象都是 指针指向对象的地址, 指针指向堆内存中的地址,因此方法二会由于多线程访问而形成坏内存访问,而TaggedPointer 则不会建立内存,而是在isa指针上作手脚。在指针上存放具体值。atom
64位开始 引入了Tagged Pointer 技术,用于优化NSNumber、NSDate、NSString 等小对象存储spa
从上图能够看出 0结尾的为对象地址 由于以16位为基准 内存对齐线程
而方法二的明显不同。指针
objc_release(id obj)
{
if (!obj) return;
if (obj->isTaggedPointer()) return;
return obj->release();
}
复制代码
当obj为isTaggedPointer的时候 直接返回。 因此更加验证了刚才的说法 即:用指针存值,而不是在堆中生成对象
objc_object::isTaggedPointer()
{
return _objc_isTaggedPointer(this);
}
复制代码
# define _OBJC_TAG_MASK 1UL
static inline bool
_objc_isTaggedPointer(const void * _Nullable ptr)
{
return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
复制代码
#if (TARGET_OS_OSX || TARGET_OS_IOSMAC) && __x86_64__ //若是是OSX && X86
// 64-bit Mac - tag bit is LSB
# define OBJC_MSB_TAGGED_POINTERS 0
#else //其余状况 包含iOS
// Everything else - tag bit is MSB
# define OBJC_MSB_TAGGED_POINTERS 1
#endif
#if OBJC_MSB_TAGGED_POINTERS
# define _OBJC_TAG_MASK (1UL<<63) //若是是OSX && X86
#else
# define _OBJC_TAG_MASK 1UL //其余状况 包含iOS
#endif
复制代码
从上面能够看当在OSX && X86
出当1UL<<63
为1的时候为TaggedPointer
从上面能够看当在iOS平台
出当尾数为1的时候为TaggedPointer
感兴趣的能够关注个人公众号。天天会更新哦 很是感谢。相互交流 提高技术~