基本概念
首先,那些对象才需要我们进行内存管理呢?
- 任何继承了NSObject的对象需要进行内存管理
- 而其他非对象类型(int、char、float、double、struct、enum等) 不需要进行内存管理
这是因为
- 继承了NSObject的对象的存储在操作系统的
堆
里边。 - 操作系统的
堆
:一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表 - 非OC对象一般放在操作系统的
栈
里面 - 操作系统的
栈
:由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈(先进后出) - 示例
int main(int argc, const char * argv[])
{
@autoreleasepool {
int a = 10; // 栈
int b = 20; // 栈
// p : 栈
// Person对象(计数器==1) : 堆
Person *p = [[Person alloc] init];
}
// 经过上面代码后, 栈里面的变量a、b、p 都会被回收
// 但是堆里面的Person对象还会留在内存中,因为它是计数器依然是1
return 0;
}
ARC
使用ARC后,系统会检测出何时需要保持对象,何时需要自动释放对象,何时需要释放对象,编译器会管理好对象的内存,会在何时的地方插入retain, release和autorelease,通过生成正确的代码去自动释放或者保持对象。我们完全不用担心编译器会出错
1. ARC的判断原则
ARC判断一个对象是否需要释放不是通过引用计数来进行判断的,而是通过强指针来进行判断的。那么什么是强指针?
- 强指针
- 默认所有对象的指针变量都是强指针
- 被__strong修饰的指针
Person *p1 = [[Person alloc] init];
__strong Person *p2 = [[Person alloc] init];
- 弱指针
- 被__weak修饰的指针
__weak Person *p = [[Person alloc] init];
ARC如何通过强指针来判断?
- 只要还有一个强指针变量指向对象,对象就会保持在内存中
2. ARC的使用
int main(int argc, const char * argv[]) {
// 不用写release, main函数执行完毕后p会被自动释放
Person *p = [[Person alloc] init];
return 0;
}
3. ARC的注意点
- 不允许调用对象的 release方法
- 不允许调用 autorelease方法
- 重写父类的dealloc方法时,不能再调用 [super dealloc];
4.ARC 下单对象内存管理
- 局部变量释放对象随之释放
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc] init];
} // 执行到这一行局部变量p释放
// 由于没有强指针指向对象, 所以对象也释放
return 0;
}
- 清空指针对象随之被释放
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc] init];
p = nil; // 执行到这一行, 由于没有强指针指向对象, 所以对象被释放
}
return 0;
}
- 默认所有指针都是强指针
int main(int argc, const char * argv[]) {
@autoreleasepool {
// p1和p2都是强指针
Person *p1 = [[Person alloc] init];
__strong Person *p2 = [[Person alloc] init];
}
return 0;
}
- 弱指针需要明确说明
- 注意: 千万不要使用弱指针保存新创建的对象
int main(int argc, const char * argv[]) {
@autoreleasepool {
// p是弱指针, 对象会被立即释放
__weak Person *p1 = [[Person alloc] init];
}
return 0;
}
5. ARC下多对象内存管理
- ARC和MRC一样, 想拥有某个对象必须用强指针保存对象, 但是不需要在dealloc方法中release
@interface Person : NSObject
// MRC写法
//@property (nonatomic, retain) Dog *dog;
// ARC写法
@property (nonatomic, strong) Dog *dog;
@end
6. ARC下循环引用问题
- ARC和MRC一样,如果A拥有B,B也拥有A,那么必须一方使用弱指针
@interface Person : NSObject
@property (nonatomic, strong) Dog *dog;
@end
@interface Dog : NSObject
// 错误写法, 循环引用会导致内存泄露
//@property (nonatomic, strong) Person *owner;
// 正确写法, 当如果保存对象建议使用weak
@property (nonatomic, weak) Person *owner;
@end
参考自简书