@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
感興趣的能夠關注個人公衆號。天天會更新哦 很是感謝。相互交流 提高技術~