Tagged Pointer

先解決個問題

首先定義
@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

TaggedPointer

64位開始 引入了Tagged Pointer 技術,用於優化NSNumber、NSDate、NSString 等小對象存儲spa

打印方式1、方式二的NSString地址

從上圖能夠看出 0結尾的爲對象地址 由於以16位爲基準 內存對齊線程

而方法二的明顯不同。指針

咱們看一下objc_release的源碼
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

感興趣的能夠關注個人公衆號。天天會更新哦 很是感謝。相互交流 提高技術~

相關文章
相關標籤/搜索