最近在研究内存管理,所以看了很多runtime底层的代码,越深入探索越觉得自己在理解上还是出现了部分偏差,现在重新整理记录一下,以防自己忘了。
引用计数
在iOS中,用引用计数来管理内存,在创建一个对象时,首先在内存中开辟一块内存空间,引用计数变为1,告诉系统这块内存不能释放,在有指针指向这个对象时,引用计数+1,当这个指向对象的指针变成nil时,对象引用计数-1,当引用计数为0时销毁这块内存,说白了引用计数就是指一块内存地址上有几个指针(指向)。下面举例来看一下。
NSObject *obj1 = [NSObject new];
NSObject *obj2 = obj1;
__weak NSObject *obj3 = obj1;
NSObject *obj4 = obj1;
NSObject *obj5 = obj3;
printf("obj1:%ld\n", CFGetRetainCount((__bridge CFTypeRef)(obj1)));
printf("obj2:%ld\n", CFGetRetainCount((__bridge CFTypeRef)(obj2)));
printf("obj3:%ld\n", CFGetRetainCount((__bridge CFTypeRef)(obj3)));
printf("obj4:%ld\n", CFGetRetainCount((__bridge CFTypeRef)(obj4)));
printf("obj5:%ld\n", CFGetRetainCount((__bridge CFTypeRef)(obj5)));
我们分三步来解析这段代码
- 从控制栏左侧我们可以看出,obj1、obj2、obj3的内存地址(0x6xxxx),0x6开头的是堆内存地址,它们三个享有共同的内存地址。
- 再看右侧控制栏,我们分别打印一下它们的指针地址,发现它们虽然内存地址一样,但是指针地址是不一样的,指针地址指向同一块内存。
-
最后看一下它们的引用计数,引用计数就是在数这个内存地址上有几个指针在指向。如下图所示
1、obj1指向了内存,内存现在有一个指针,retainCount = 1
2、obj2强引用了obj1,所以也指向了内存,retainCount+1
3、obj3弱引用了obj1,在obj3看来“我就是指向了内存”,但在其他人看来他没有指向内存,所以其他人retainCount不变,obj3的retainCount+1。
4、obj4强引用了obj1,所以也指向了内存,retainCount+1
5、obj5强引用了obj3,而obj3指向内存,所以obj5也指向内存,retainCount+1
综上,在obj1、obj2、obj4、obj5看来,这块内存有4个指针即retainCount=4,在obj3看来,自己也算是指向内存了,所以obj3的retainCount=5。