iOS多线程导致Exc_Bad原因查找过程记录
不知道大家有没有这样的疑问,参数被使用前,肯定都被 retain 了,那为什么还会因为提前释放而闪退呢?
看汇编经验:
- 查看栈:x/nxg, n是个数,rbp是栈里面地址最大的,所以要减去栈的长度,才能看到整个栈的数据 https://www.jianshu.com/p/1005ccfe8fea
- 模拟器寄存器规律:
- rax总是接收返回值的
- rdi总是第一个参数,如果是obj_msg的话,是消息接收者(self)
- rsi总是第二个参数,如果是obj_msg的话,是selector
- 参数的retain是在被调用的方法内部做的
- rdx可能是第三个参数
- 凡是看到调用方法前,被赋值的寄存器,都有可能是被调用的方法中要用到的
- 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
总结来看就是这样的:
- 获取到 self.arr,把上一步结果 retain,也就是retain self.arr,获取到 [self.arr class],对上一步的结果做 stringfromclass,得到字符串,对上一步的结果 retain
- 获取到 self.arr,把上一步结果 retain,也就是retain self.arr,对上一步结果做 CFGetRetainCount
- 执行NSLog
- 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
总结来看就是这样的:
- 获取到 self.arr,retain 上一步结果,并存在栈中 rbp-18
- 对rbp-18 做 stringfromclass,得到字符串,对上一步的结果 retain
- 对rbp-18做 CFGetRetainCount
- 执行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
虽然还没有确切的证据,但我觉得之所以会闪退是因为给局部变量 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 }
以此也能佐证我上面的结论