iOS多线程导致Exc_Bad原因查找过程记录

不知道大家有没有这样的疑问,参数被使用前,肯定都被 retain 了,那为什么还会因为提前释放而闪退呢?

看汇编经验:

  1. 查看栈:x/nxg, n是个数,rbp是栈里面地址最大的,所以要减去栈的长度,才能看到整个栈的数据 https://www.jianshu.com/p/1005ccfe8fea
  2. 模拟器寄存器规律:
    1. rax总是接收返回值的
    2. rdi总是第一个参数,如果是obj_msg的话,是消息接收者(self)
    3. rsi总是第二个参数,如果是obj_msg的话,是selector
    4. 参数的retain是在被调用的方法内部做的
    5. rdx可能是第三个参数
    6. 凡是看到调用方法前,被赋值的寄存器,都有可能是被调用的方法中要用到的
    7. leaq:load effective address,也就是取地址操作

第一个实验🧪

 1 #define kTJJLog(obj, msg) NSLog(@"%@ %@, %ld", msg, NSStringFromClass([obj class]), CFGetRetainCount((__bridge CFTypeRef)(obj)));
 2 - (void)mul {
 3     People1 *p = [People1 people1WithFirstName:@"0" lastName:@"0" age:1];
 4     NSArray *arr = @[p];
 5     self.arr = arr;
 6     kTJJLog(arr, @"执行 block")
 7     kTJJLog(p, @"执行 block")
 8 }
 9 
10 - (void)mul {
11   People1 *p = [People1 people1WithFirstName:@"0" lastName:@"0" age:1];
12     NSArray *arr = @[p];
13     self.arr = arr;
14     kTJJLog(self.arr, @"执行 block")
15     kTJJLog(self.arr[0], @"执行 block")
16 }

第一种写法的打印结果如果是3的话,第二种写法的结果就是4,第二种写法的引用计数比第一种多1,这是为什么呢?

 

以下是第一种写法的汇编代码:

  1 Test`-[AppDelegate mul]:
  2     0x10c7de190 <+0>:   pushq  %rbp
  3     0x10c7de191 <+1>:   movq   %rsp, %rbp
  4     0x10c7de194 <+4>:   subq   $0x70, %rsp
  5     0x10c7de198 <+8>:   leaq   0xefd9(%rip), %rax        ; @"'0'"
  6     0x10c7de19f <+15>:  movq   0xdf9a(%rip), %rcx        ; (void *)0x00007fff89cb95c0: __stack_chk_guard
  7     0x10c7de1a6 <+22>:  movq   (%rcx), %rcx
  8     0x10c7de1a9 <+25>:  movq   %rcx, -0x8(%rbp)
  9     0x10c7de1ad <+29>:  movq   %rdi, -0x18(%rbp)
 10     0x10c7de1b1 <+33>:  movq   %rsi, -0x20(%rbp)
 11     0x10c7de1b5 <+37>:  movq   0x12784(%rip), %rcx       ; (void *)0x000000010c7f0b78: People1
 12     0x10c7de1bc <+44>:  movq   0x1269d(%rip), %rsi       ; "people1WithFirstName:lastName:age:"
 13     0x10c7de1c3 <+51>:  movq   %rcx, %rdi
 14     0x10c7de1c6 <+54>:  movq   %rax, %rdx
 15     0x10c7de1c9 <+57>:  movq   %rax, %rcx
 16     0x10c7de1cc <+60>:  movl   $0x1, %r8d
 17     0x10c7de1d2 <+66>:  callq  *0xdf98(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 18     0x10c7de1d8 <+72>:  movq   %rax, %rdi
 19     0x10c7de1db <+75>:  callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 20     0x10c7de1e0 <+80>:  movq   %rax, -0x28(%rbp)
 21     0x10c7de1e4 <+84>:  movq   -0x28(%rbp), %rax
 22     0x10c7de1e8 <+88>:  movq   %rax, -0x10(%rbp)
 23     0x10c7de1ec <+92>:  movq   0x12705(%rip), %rax       ; (void *)0x00007fff87a919f8: NSArray
 24     0x10c7de1f3 <+99>:  movq   0x124e6(%rip), %rsi       ; "arrayWithObjects:count:"
 25     0x10c7de1fa <+106>: leaq   -0x10(%rbp), %rcx
 26     0x10c7de1fe <+110>: movq   %rax, %rdi
 27     0x10c7de201 <+113>: movq   %rcx, %rdx
 28     0x10c7de204 <+116>: movl   $0x1, %ecx
 29     0x10c7de209 <+121>: callq  *0xdf61(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 30     0x10c7de20f <+127>: movq   %rax, %rdi
 31     0x10c7de212 <+130>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 32     0x10c7de217 <+135>: movq   %rax, -0x30(%rbp)
 33     0x10c7de21b <+139>: movq   -0x30(%rbp), %rdx
 34     0x10c7de21f <+143>: movq   -0x18(%rbp), %rax
 35     0x10c7de223 <+147>: movq   0x1263e(%rip), %rsi       ; "setArr:"
 36     0x10c7de22a <+154>: movq   %rax, %rdi
 37     0x10c7de22d <+157>: callq  *0xdf3d(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 38     0x10c7de233 <+163>: movq   -0x18(%rbp), %rax
 39     0x10c7de237 <+167>: movq   0x12632(%rip), %rsi       ; "arr"
 40     0x10c7de23e <+174>: movq   %rax, %rdi
 41     0x10c7de241 <+177>: callq  *0xdf29(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 42     0x10c7de247 <+183>: movq   %rax, %rdi
 43     0x10c7de24a <+186>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 44     0x10c7de24f <+191>: movq   0x12002(%rip), %rsi       ; "class"
 45     0x10c7de256 <+198>: movq   %rax, %rcx
 46     0x10c7de259 <+201>: movq   %rcx, %rdi
 47     0x10c7de25c <+204>: movq   %rax, -0x38(%rbp)
 48     0x10c7de260 <+208>: callq  *0xdf0a(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 49     0x10c7de266 <+214>: movq   %rax, %rdi
 50     0x10c7de269 <+217>: callq  0x10c7e72e8               ; symbol stub for: NSStringFromClass
 51     0x10c7de26e <+222>: movq   %rax, %rdi
 52     0x10c7de271 <+225>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 53     0x10c7de276 <+230>: movq   -0x18(%rbp), %rcx
 54     0x10c7de27a <+234>: movq   0x125ef(%rip), %rsi       ; "arr"
 55     0x10c7de281 <+241>: movq   %rcx, %rdi
 56     0x10c7de284 <+244>: movq   %rax, -0x40(%rbp)
 57     0x10c7de288 <+248>: callq  *0xdee2(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 58     0x10c7de28e <+254>: movq   %rax, %rdi
 59     0x10c7de291 <+257>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 60     0x10c7de296 <+262>: movq   %rax, %rcx
 61     0x10c7de299 <+265>: movq   %rcx, %rdi
 62     0x10c7de29c <+268>: movq   %rax, -0x48(%rbp)
 63     0x10c7de2a0 <+272>: callq  0x10c7e72d0               ; symbol stub for: CFGetRetainCount
 64     0x10c7de2a5 <+277>: leaq   0xeeec(%rip), %rcx        ; @"%@ %@, %ld"
 65     0x10c7de2ac <+284>: leaq   0xef05(%rip), %rdx        ; @
 66     0x10c7de2b3 <+291>: movq   %rcx, %rdi
 67     0x10c7de2b6 <+294>: movq   %rdx, %rsi
 68     0x10c7de2b9 <+297>: movq   -0x40(%rbp), %rdx
 69     0x10c7de2bd <+301>: movq   %rax, %rcx
 70     0x10c7de2c0 <+304>: movb   $0x0, %al
 71     0x10c7de2c2 <+306>: callq  0x10c7e72e2               ; symbol stub for: NSLog
 72     0x10c7de2c7 <+311>: movq   -0x48(%rbp), %rcx
 73     0x10c7de2cb <+315>: movq   %rcx, %rdi
 74     0x10c7de2ce <+318>: callq  *0xdea4(%rip)             ; (void *)0x00007fff50bbe940: objc_release
 75     0x10c7de2d4 <+324>: movq   -0x40(%rbp), %rcx
 76     0x10c7de2d8 <+328>: movq   %rcx, %rdi
 77     0x10c7de2db <+331>: callq  *0xde97(%rip)             ; (void *)0x00007fff50bbe940: objc_release
 78     0x10c7de2e1 <+337>: movq   -0x38(%rbp), %rcx
 79     0x10c7de2e5 <+341>: movq   %rcx, %rdi
 80     0x10c7de2e8 <+344>: callq  *0xde8a(%rip)             ; (void *)0x00007fff50bbe940: objc_release
 81 ->  0x10c7de2ee <+350>: movq   -0x18(%rbp), %rcx
 82     0x10c7de2f2 <+354>: movq   0x12577(%rip), %rsi       ; "arr"
 83     0x10c7de2f9 <+361>: movq   %rcx, %rdi
 84     0x10c7de2fc <+364>: callq  *0xde6e(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 85     0x10c7de302 <+370>: movq   %rax, %rdi
 86     0x10c7de305 <+373>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 87     0x10c7de30a <+378>: xorl   %r9d, %r9d
 88     0x10c7de30d <+381>: movl   %r9d, %edx
 89     0x10c7de310 <+384>: movq   0x12229(%rip), %rsi       ; "objectAtIndexedSubscript:"
 90     0x10c7de317 <+391>: movq   %rax, %rcx
 91     0x10c7de31a <+394>: movq   %rcx, %rdi
 92     0x10c7de31d <+397>: movq   %rax, -0x50(%rbp)
 93     0x10c7de321 <+401>: callq  *0xde49(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 94     0x10c7de327 <+407>: movq   %rax, %rdi
 95     0x10c7de32a <+410>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 96     0x10c7de32f <+415>: movq   0x11f22(%rip), %rsi       ; "class"
 97     0x10c7de336 <+422>: movq   %rax, %rdi
 98     0x10c7de339 <+425>: movq   %rax, -0x58(%rbp)
 99     0x10c7de33d <+429>: callq  *0xde2d(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
100     0x10c7de343 <+435>: movq   %rax, %rdi
101     0x10c7de346 <+438>: callq  0x10c7e72e8               ; symbol stub for: NSStringFromClass
102     0x10c7de34b <+443>: movq   %rax, %rdi
103     0x10c7de34e <+446>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
104     0x10c7de353 <+451>: movq   -0x18(%rbp), %rcx
105     0x10c7de357 <+455>: movq   0x12512(%rip), %rsi       ; "arr"
106     0x10c7de35e <+462>: movq   %rcx, %rdi
107     0x10c7de361 <+465>: movq   %rax, -0x60(%rbp)
108     0x10c7de365 <+469>: callq  *0xde05(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
109     0x10c7de36b <+475>: movq   %rax, %rdi
110     0x10c7de36e <+478>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
111     0x10c7de373 <+483>: xorl   %r9d, %r9d
112     0x10c7de376 <+486>: movl   %r9d, %edx
113     0x10c7de379 <+489>: movq   0x121c0(%rip), %rsi       ; "objectAtIndexedSubscript:"
114     0x10c7de380 <+496>: movq   %rax, %rcx
115     0x10c7de383 <+499>: movq   %rcx, %rdi
116     0x10c7de386 <+502>: movq   %rax, -0x68(%rbp)
117     0x10c7de38a <+506>: callq  *0xdde0(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
118     0x10c7de390 <+512>: movq   %rax, %rdi
119     0x10c7de393 <+515>: callq  0x10c7e73ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
120     0x10c7de398 <+520>: movq   %rax, %rdi
121     0x10c7de39b <+523>: movq   %rax, -0x70(%rbp)
122     0x10c7de39f <+527>: callq  0x10c7e72d0               ; symbol stub for: CFGetRetainCount
123     0x10c7de3a4 <+532>: leaq   0xeded(%rip), %rcx        ; @"%@ %@, %ld"
124     0x10c7de3ab <+539>: leaq   0xee06(%rip), %rdx        ; @
125     0x10c7de3b2 <+546>: movq   %rcx, %rdi
126     0x10c7de3b5 <+549>: movq   %rdx, %rsi
127     0x10c7de3b8 <+552>: movq   -0x60(%rbp), %rdx
128     0x10c7de3bc <+556>: movq   %rax, %rcx
129     0x10c7de3bf <+559>: movb   $0x0, %al
130     0x10c7de3c1 <+561>: callq  0x10c7e72e2               ; symbol stub for: NSLog
131     0x10c7de3c6 <+566>: movq   -0x70(%rbp), %rdi
132     0x10c7de3ca <+570>: callq  *0xdda8(%rip)             ; (void *)0x00007fff50bbe940: objc_release
133     0x10c7de3d0 <+576>: movq   -0x68(%rbp), %rcx
134     0x10c7de3d4 <+580>: movq   %rcx, %rdi
135     0x10c7de3d7 <+583>: callq  *0xdd9b(%rip)             ; (void *)0x00007fff50bbe940: objc_release
136     0x10c7de3dd <+589>: movq   -0x60(%rbp), %rcx
137     0x10c7de3e1 <+593>: movq   %rcx, %rdi
138     0x10c7de3e4 <+596>: callq  *0xdd8e(%rip)             ; (void *)0x00007fff50bbe940: objc_release
139     0x10c7de3ea <+602>: movq   -0x58(%rbp), %rdi
140     0x10c7de3ee <+606>: callq  *0xdd84(%rip)             ; (void *)0x00007fff50bbe940: objc_release
141     0x10c7de3f4 <+612>: movq   -0x50(%rbp), %rcx
142     0x10c7de3f8 <+616>: movq   %rcx, %rdi
143     0x10c7de3fb <+619>: callq  *0xdd77(%rip)             ; (void *)0x00007fff50bbe940: objc_release
144     0x10c7de401 <+625>: xorl   %r9d, %r9d
145     0x10c7de404 <+628>: movl   %r9d, %esi
146     0x10c7de407 <+631>: leaq   -0x30(%rbp), %rcx
147     0x10c7de40b <+635>: movq   %rcx, %rdi
148     0x10c7de40e <+638>: callq  0x10c7e73d2               ; symbol stub for: objc_storeStrong
149     0x10c7de413 <+643>: xorl   %r9d, %r9d
150     0x10c7de416 <+646>: movl   %r9d, %esi
151     0x10c7de419 <+649>: leaq   -0x28(%rbp), %rcx
152     0x10c7de41d <+653>: movq   %rcx, %rdi
153     0x10c7de420 <+656>: callq  0x10c7e73d2               ; symbol stub for: objc_storeStrong
154     0x10c7de425 <+661>: movq   0xdd14(%rip), %rcx        ; (void *)0x00007fff89cb95c0: __stack_chk_guard
155     0x10c7de42c <+668>: movq   (%rcx), %rcx
156     0x10c7de42f <+671>: movq   -0x8(%rbp), %rdx
157     0x10c7de433 <+675>: cmpq   %rdx, %rcx
158     0x10c7de436 <+678>: jne    0x10c7de442               ; <+690> at AppDelegate.m
159     0x10c7de43c <+684>: addq   $0x70, %rsp
160     0x10c7de440 <+688>: popq   %rbp
161     0x10c7de441 <+689>: retq   
162     0x10c7de442 <+690>: callq  0x10c7e7306               ; symbol stub for: __stack_chk_fail
163     0x10c7de447 <+695>: ud2    
View Code

总结来看就是这样的:

  1. 获取到 self.arr,把上一步结果 retain,也就是retain self.arr,获取到 [self.arr class],对上一步的结果做 stringfromclass,得到字符串,对上一步的结果 retain
  2. 获取到 self.arr,把上一步结果 retain,也就是retain self.arr,对上一步结果做 CFGetRetainCount
  3. 执行NSLog
  4. release self.arr,release self.arr,release 字符串

第二种写法的汇编是:

  1 Test`-[AppDelegate mul]:
  2     0x10af96290 <+0>:   pushq  %rbp
  3     0x10af96291 <+1>:   movq   %rsp, %rbp
  4     0x10af96294 <+4>:   subq   $0x40, %rsp
  5     0x10af96298 <+8>:   leaq   0xeed9(%rip), %rax        ; @"'0'"
  6     0x10af9629f <+15>:  movq   0xde9a(%rip), %rcx        ; (void *)0x00007fff89cb95c0: __stack_chk_guard
  7     0x10af962a6 <+22>:  movq   (%rcx), %rcx
  8     0x10af962a9 <+25>:  movq   %rcx, -0x8(%rbp)
  9     0x10af962ad <+29>:  movq   %rdi, -0x18(%rbp)
 10     0x10af962b1 <+33>:  movq   %rsi, -0x20(%rbp)
 11     0x10af962b5 <+37>:  movq   0x1267c(%rip), %rcx       ; (void *)0x000000010afa8b70: People1
 12     0x10af962bc <+44>:  movq   0x1259d(%rip), %rsi       ; "people1WithFirstName:lastName:age:"
 13     0x10af962c3 <+51>:  movq   %rcx, %rdi
 14     0x10af962c6 <+54>:  movq   %rax, %rdx
 15     0x10af962c9 <+57>:  movq   %rax, %rcx
 16     0x10af962cc <+60>:  movl   $0x1, %r8d
 17     0x10af962d2 <+66>:  callq  *0xde98(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 18     0x10af962d8 <+72>:  movq   %rax, %rdi
 19     0x10af962db <+75>:  callq  0x10af9f3ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 20     0x10af962e0 <+80>:  movq   %rax, -0x28(%rbp)
 21     0x10af962e4 <+84>:  movq   -0x28(%rbp), %rax
 22     0x10af962e8 <+88>:  movq   %rax, -0x10(%rbp)
 23     0x10af962ec <+92>:  movq   0x125fd(%rip), %rax       ; (void *)0x00007fff87a919f8: NSArray
 24     0x10af962f3 <+99>:  movq   0x123e6(%rip), %rsi       ; "arrayWithObjects:count:"
 25     0x10af962fa <+106>: leaq   -0x10(%rbp), %rcx
 26     0x10af962fe <+110>: movq   %rax, %rdi
 27     0x10af96301 <+113>: movq   %rcx, %rdx
 28     0x10af96304 <+116>: movl   $0x1, %ecx
 29     0x10af96309 <+121>: callq  *0xde61(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 30     0x10af9630f <+127>: movq   %rax, %rdi
 31     0x10af96312 <+130>: callq  0x10af9f3ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 32     0x10af96317 <+135>: movq   %rax, -0x30(%rbp)
 33     0x10af9631b <+139>: movq   -0x30(%rbp), %rdx
 34     0x10af9631f <+143>: movq   -0x18(%rbp), %rax
 35     0x10af96323 <+147>: movq   0x1253e(%rip), %rsi       ; "setArr:"
 36     0x10af9632a <+154>: movq   %rax, %rdi
 37     0x10af9632d <+157>: callq  *0xde3d(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 38     0x10af96333 <+163>: movq   -0x30(%rbp), %rax
 39     0x10af96337 <+167>: movq   0x11f1a(%rip), %rsi       ; "class"
 40     0x10af9633e <+174>: movq   %rax, %rdi
 41     0x10af96341 <+177>: callq  *0xde29(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 42     0x10af96347 <+183>: movq   %rax, %rdi
 43     0x10af9634a <+186>: callq  0x10af9f2e8               ; symbol stub for: NSStringFromClass
 44     0x10af9634f <+191>: movq   %rax, %rdi
 45     0x10af96352 <+194>: callq  0x10af9f3ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 46     0x10af96357 <+199>: movq   -0x30(%rbp), %rcx
 47     0x10af9635b <+203>: movq   %rcx, %rdi
 48     0x10af9635e <+206>: movq   %rax, -0x38(%rbp)
 49     0x10af96362 <+210>: callq  0x10af9f2d0               ; symbol stub for: CFGetRetainCount
 50     0x10af96367 <+215>: leaq   0xee2a(%rip), %rcx        ; @"%@ %@, %ld"
 51     0x10af9636e <+222>: leaq   0xee43(%rip), %rdx        ; @
 52     0x10af96375 <+229>: movq   %rcx, %rdi
 53     0x10af96378 <+232>: movq   %rdx, %rsi
 54     0x10af9637b <+235>: movq   -0x38(%rbp), %rdx
 55     0x10af9637f <+239>: movq   %rax, %rcx
 56     0x10af96382 <+242>: movb   $0x0, %al
 57     0x10af96384 <+244>: callq  0x10af9f2e2               ; symbol stub for: NSLog
 58     0x10af96389 <+249>: movq   -0x38(%rbp), %rcx
 59     0x10af9638d <+253>: movq   %rcx, %rdi
 60     0x10af96390 <+256>: callq  *0xdde2(%rip)             ; (void *)0x00007fff50bbe940: objc_release
 61 ->  0x10af96396 <+262>: movq   -0x28(%rbp), %rcx
 62     0x10af9639a <+266>: movq   0x11eb7(%rip), %rsi       ; "class"
 63     0x10af963a1 <+273>: movq   %rcx, %rdi
 64     0x10af963a4 <+276>: callq  *0xddc6(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
 65     0x10af963aa <+282>: movq   %rax, %rdi
 66     0x10af963ad <+285>: callq  0x10af9f2e8               ; symbol stub for: NSStringFromClass
 67     0x10af963b2 <+290>: movq   %rax, %rdi
 68     0x10af963b5 <+293>: callq  0x10af9f3ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
 69     0x10af963ba <+298>: movq   -0x28(%rbp), %rcx
 70     0x10af963be <+302>: movq   %rcx, %rdi
 71     0x10af963c1 <+305>: movq   %rax, -0x40(%rbp)
 72     0x10af963c5 <+309>: callq  0x10af9f2d0               ; symbol stub for: CFGetRetainCount
 73     0x10af963ca <+314>: leaq   0xedc7(%rip), %rcx        ; @"%@ %@, %ld"
 74     0x10af963d1 <+321>: leaq   0xede0(%rip), %rdx        ; @
 75     0x10af963d8 <+328>: movq   %rcx, %rdi
 76     0x10af963db <+331>: movq   %rdx, %rsi
 77     0x10af963de <+334>: movq   -0x40(%rbp), %rdx
 78     0x10af963e2 <+338>: movq   %rax, %rcx
 79     0x10af963e5 <+341>: movb   $0x0, %al
 80     0x10af963e7 <+343>: callq  0x10af9f2e2               ; symbol stub for: NSLog
 81     0x10af963ec <+348>: movq   -0x40(%rbp), %rcx
 82     0x10af963f0 <+352>: movq   %rcx, %rdi
 83     0x10af963f3 <+355>: callq  *0xdd7f(%rip)             ; (void *)0x00007fff50bbe940: objc_release
 84     0x10af963f9 <+361>: xorl   %r9d, %r9d
 85     0x10af963fc <+364>: movl   %r9d, %esi
 86     0x10af963ff <+367>: leaq   -0x30(%rbp), %rcx
 87     0x10af96403 <+371>: movq   %rcx, %rdi
 88     0x10af96406 <+374>: callq  0x10af9f3d2               ; symbol stub for: objc_storeStrong
 89     0x10af9640b <+379>: xorl   %r9d, %r9d
 90     0x10af9640e <+382>: movl   %r9d, %esi
 91     0x10af96411 <+385>: leaq   -0x28(%rbp), %rcx
 92     0x10af96415 <+389>: movq   %rcx, %rdi
 93     0x10af96418 <+392>: callq  0x10af9f3d2               ; symbol stub for: objc_storeStrong
 94     0x10af9641d <+397>: movq   0xdd1c(%rip), %rcx        ; (void *)0x00007fff89cb95c0: __stack_chk_guard
 95     0x10af96424 <+404>: movq   (%rcx), %rcx
 96     0x10af96427 <+407>: movq   -0x8(%rbp), %rdx
 97     0x10af9642b <+411>: cmpq   %rdx, %rcx
 98     0x10af9642e <+414>: jne    0x10af9643a               ; <+426> at AppDelegate.m
 99     0x10af96434 <+420>: addq   $0x40, %rsp
100     0x10af96438 <+424>: popq   %rbp
101     0x10af96439 <+425>: retq   
102     0x10af9643a <+426>: callq  0x10af9f306               ; symbol stub for: __stack_chk_fail
103     0x10af9643f <+431>: ud2    
View Code

总结来看就是这样的:

  1. 获取到 self.arr,retain 上一步结果,并存在栈中 rbp-18
  2. 对rbp-18 做 stringfromclass,得到字符串,对上一步的结果 retain
  3. rbp-18做 CFGetRetainCount
  4. 执行NSLog

所以第一种方式retain了两次,第二种方式retain了一次

第二个实验🧪

 1 for (NSInteger i = 0; i < 10000; i++) {
 2         [self mul];
 3 }
 4 - (void)mul {
 5     People1 *p = [People1 people1WithFirstName:@"0" lastName:@"0" age:1];
 6     NSArray *arrq = @[p];
 7     self.arr = arrq;
 8     BlankBlock block = ^{
 9         NSArray *arr = nil;
10         arr = self.arr;
11         NSInteger count = arr.count;
12         NSLog(@"%ld", count);
13     };
14     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
15 }

这个代码当然会闪退,查看汇编代码:

 1 Test`__18-[AppDelegate mul]_block_invoke:
 2     0x10dbef3c0 <+0>:   pushq  %rbp
 3     0x10dbef3c1 <+1>:   movq   %rsp, %rbp
 4     0x10dbef3c4 <+4>:   subq   $0x20, %rsp
 5     0x10dbef3c8 <+8>:   movq   %rdi, -0x8(%rbp)
 6     0x10dbef3cc <+12>:  movq   %rdi, %rax
 7     0x10dbef3cf <+15>:  movq   %rax, -0x10(%rbp)
 8     0x10dbef3d3 <+19>:  movq   $0x0, -0x18(%rbp)
 9     0x10dbef3db <+27>:  movq   0x20(%rdi), %rax
10     0x10dbef3df <+31>:  movq   0x1248a(%rip), %rsi       ; "arr"
11     0x10dbef3e6 <+38>:  movq   %rax, %rdi
12     0x10dbef3e9 <+41>:  callq  *0xdd81(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
13     0x10dbef3ef <+47>:  movq   %rax, %rdi
14     0x10dbef3f2 <+50>:  callq  0x10dbf83ae               ; symbol stub for: objc_retainAutoreleasedReturnValue
15     0x10dbef3f7 <+55>:  movq   -0x18(%rbp), %rcx
16     0x10dbef3fb <+59>:  movq   %rax, -0x18(%rbp)
17     0x10dbef3ff <+63>:  movq   %rcx, %rdi
18     0x10dbef402 <+66>:  callq  *0xdd70(%rip)             ; (void *)0x00007fff50bbe940: objc_release
19     0x10dbef408 <+72>:  movq   -0x18(%rbp), %rax
20     0x10dbef40c <+76>:  movq   0x11f7d(%rip), %rsi       ; "count"
21     0x10dbef413 <+83>:  movq   %rax, %rdi
22     0x10dbef416 <+86>:  callq  *0xdd54(%rip)             ; (void *)0x00007fff50ba4400: objc_msgSend
23 ->  0x10dbef41c <+92>:  leaq   0xed75(%rip), %rcx        ; @"%ld"
24     0x10dbef423 <+99>:  movq   %rax, -0x20(%rbp)
25     0x10dbef427 <+103>: movq   -0x20(%rbp), %rsi
26     0x10dbef42b <+107>: movq   %rcx, %rdi
27     0x10dbef42e <+110>: movb   $0x0, %al
28     0x10dbef430 <+112>: callq  0x10dbf82e2               ; symbol stub for: NSLog
29     0x10dbef435 <+117>: xorl   %edx, %edx
30     0x10dbef437 <+119>: movl   %edx, %esi
31     0x10dbef439 <+121>: leaq   -0x18(%rbp), %rcx
32     0x10dbef43d <+125>: movq   %rcx, %rdi
33     0x10dbef440 <+128>: callq  0x10dbf83d2               ; symbol stub for: objc_storeStrong
34     0x10dbef445 <+133>: addq   $0x20, %rsp
35     0x10dbef449 <+137>: popq   %rbp
36     0x10dbef44a <+138>: retq   
View Code

虽然还没有确切的证据,但我觉得之所以会闪退是因为给局部变量 arr 赋值是分成3个步骤的:

(1)取到 self.arr

(2)retain 结果

(3)赋值给 arr

因为取到之后,retain 之前,这个数组就被释放了,所以会闪退

但有问题,那为什么不是每次都在进行第三步赋值时闪退?实际情况是,有时在执行 count 时,有时在 block 执行完成后 release 数组时闪退

这可能就是很玄乎的“内存还没有被回收”的原因吧

第三个实验🧪

把代码改成这样就不会闪退了:

 1 - (void)mul {
 2     People1 *p = [People1 people1WithFirstName:@"0" lastName:@"0" age:1];
 3     NSArray *arrq = @[p];
 4     @synchronized (self) {
 5         self.arr = arrq;
 6     }
 7     BlankBlock block = ^{
 8         NSArray *arr = nil;
 9         @synchronized (self) {
10             arr = self.arr;
11         }
12         NSInteger count = arr.count;
13         NSLog(@"%ld", count);
14     };
15     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
16 }

以此也能佐证我上面的结论

posted @ 2020-06-12 16:01  小Garfield  阅读(240)  评论(0编辑  收藏  举报