RunTime源码阅读(四)内存管理

这一章节拿来做笔记,加深理解的,更详细可参考iOS 内存管理
唯一不同的,借用了计算器来验证了原文的理论。

1.内存分区

内核区、栈区(由高到低)、堆区(由低到高)、未初始化数据(.bss)、已初始化数据(.data)、代码段(.text)、保留

  1. Tagged Pointer
    专门用来存储小的对象,例如NSNumber, NSDate, NSString。
    Tagged Pointer指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc和free。
    在字符串长度在9个以内时,iOS其实使用了tagged pointer做了优化的。
  NSMutableString *mutableStr = [NSMutableString string];
  NSString *immutable = nil;
  #define _OBJC_TAG_MASK (1UL<<63)
  char c = 'a';
  do {
      [mutableStr appendFormat:@"%c", c++];
      immutable = [mutableStr copy];
      NSLog(@"%p %@ %@", immutable, immutable, immutable.class);
  }while(((uintptr_t)immutable & _OBJC_TAG_MASK) == _OBJC_TAG_MASK);

taggedPointer与string

在arm64中,当字符超过9个时,使用的是__NSCFString存储;否则是NSTaggedPointerString存储。

  1. isa 指针(NONPOINTER_ISA)
    和对象引用计数相关的有两个成员:extra_rc和has_sidetable_rc。iOS用19位的extra_rc来记录对象的引用次数,当extra_rc 不够用时,还会借助sidetable来存储计数值,这时,has_sidetable_rc会被标志为1。

标志位:
nonpointer 1bit 标志位。1(奇数)表示开启了isa优化,0(偶数)表示没有启用isa优化。所以,我们可以通过判断isa是否为奇数来判断对象是否启用了isa优化。
has_assoc 1bit 标志位。表明对象是否有关联对象。没有关联对象的对象释放的更快。
has_cxx_dtor 1bit 标志位。表明对象是否有C++或ARC析构函数。没有析构函数的对象释放的更快。
shiftcls 33bit 类指针的非零位。
magic 6bit 固定为0x1a,用于在调试时区分对象是否已经初始化。
weakly_referenced 1bit 标志位。用于表示该对象是否被别的对象弱引用。没有被弱引用的对象释放的更快。
deallocating 1bit 标志位。用于表示该对象是否正在被释放。
has_sidetable_rc 1bit 标志位。用于标识是否当前的引用计数过大,无法在isa中存储,而需要借用sidetable来存储。(这种情况大多不会发生)
extra_rc 19bit 对象的引用计数减1。比如,一个object对象的引用计数为7,则此时extra_rc的值为6。

isa指针的结构

至此我们可以验证当一个对象有关联对象、weak及引用计数。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    MyObj *obj = [[MyObj alloc] init];
    NSLog(@"1. obj isa_t = %p", *(void **)(__bridge void*)obj);
    _obj1 = obj;
    MyObj *tmpObj = obj;
    NSLog(@"2. obj isa_t = %p", *(void **)(__bridge void*)obj);
    
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"3. obj isa_t = %p", *(void **)(__bridge void*)_obj1);
    _obj2 = _obj1;
    NSLog(@"4. obj isa_t = %p", *(void **)(__bridge void*)_obj1);
    _weakRefObj = _obj1;
    NSLog(@"5. obj isa_t = %p", *(void **)(__bridge void*)_obj1);
    NSObject *attachObj = [[NSObject alloc] init];
    objc_setAssociatedObject(_obj1, "attachKey", attachObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    NSLog(@"6. obj isa_t = %p", *(void **)(__bridge void*)_obj1);
}
必须用真机,结果:
1. obj isa_t = 0x1a10547b411
 2. obj isa_t = 0x41a10547b411
 3. obj isa_t = 0x1a10547b411
 4. obj isa_t = 0x21a10547b411
 5. obj isa_t = 0x25a10547b411
 6. obj isa_t = 0x25a10547b413

MyObj就是一个普通的类。打印指向对象的指针。


打开Mac计算器,使用编程器

2.1 0x1a10547b411


0x1a10547b411

0-63表示arm64位
第0位表示开启isa指针优化,是1;如果是模拟器则不会。
第1位表示关联对象has_assoc,为0
第42位表示weakly,为0
第45到63表示引用计数,注意到extra_rc此时为0,因为引用计数等于extra_rc + 1,因此,obj进行了alloc,引用计数为1,和我们的预期一致。

2.2 0x41a10547b411


0x41a10547b411

第1位表示关联对象has_assoc,为0
第42位表示weakly,为0
第45到63表示引用计数,注意到extra_rc=2,因为引用计数等于extra_rc + 1=3,因此,_obj1引用,tmpObj也引用,即计数是3,和我们的预期一致。

2.3 0x1a10547b411


0x1a10547b411

第1位表示关联对象has_assoc,为0
第42位表示weakly,为0
第45到63表示引用计数,注意到extra_rc=0,因为引用计数等于extra_rc + 1=1,程序执行到了viewDidAppear方法,因为此时栈上变量obj ,tmpObj已经释放,因此引用计数应该减2,等于1。和我们的预期一致。

2.4 0x21a10547b411


0x21a10547b411

第1位表示关联对象has_assoc,为0
第42位表示weakly,为0
第45到63表示引用计数,注意到extra_rc=1,因为引用计数等于extra_rc + 1=2,此时_objc2也持有了_objc1,即计数是2。和我们的预期一致。

2.5 0x25a10547b411


0x25a10547b411

第1位表示关联对象has_assoc,为0
第42位表示weakly,为1
第45到63表示引用计数,计数还是2.
_weakRefObj = _obj1;没有改变本来的引用计数。但第42位标志位发生变化。
和我们的预期一致。

2.6 0x25a10547b413


0x25a10547b413

第1位表示关联对象has_assoc,为1
第42位表示weakly,为0
第45到63表示引用计数,计数还是xtra_rc + 1=2.
objc_setAssociatedObject不会改变引用计数。但第1位标志位发生变化。其他位保持不变。
和我们的预期一致。

  1. SideTable
    只有当extra_rc的二进制位不够用时,才会借助sideTable存储计数。同时SideTable也会管理weak的存储。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容

  • 1、内存布局 stack:方法调用 heap:通过alloc等分配对象 bss:未初始化的全局变量等。 data:...
    AKyS佐毅阅读 1,596评论 0 19
  • 原文链接OC内存管理--引用计数器 更新于2020-02-14 更新Tagged Pointer的知识点 引用计数...
    NeroXie阅读 2,310评论 0 6
  • iOS中内存管理机制是开发中一项很重要的知识,了解iOS中内存管理的规则不管是在开发中还是在学习中都能很大程度的帮...
    Mr_Atom阅读 3,409评论 1 4
  • Runtime源码剖析---图解引用计数与weak 在iOS开发过程中,会经常使用到一个修饰词“weak”,使用场...
    祀梦_阅读 1,021评论 2 10
  • iOS中内存管理机制是开发中一项很重要的知识,了解iOS中内存管理的规则不管是在开发中还是在学习中都能很大程度的帮...
    Horson19阅读 1,204评论 0 4