//这个方法结束后,栈里的变量a、p会被回收,堆里的Person对象还会留在内存中,因为它的引用计数还是1
-(void)doSomething{
//a:栈
int a = 10;
//p:栈
//Person:堆
Person *p = [[Person alloc]init];
}
OC语言使用引用计数来管理内存,每一个对象都有一个可以递增递减的计数器,如果引用这个对象,那么这个对象的引用计数递增,如果不用了,那么这个对象引用计数递减,直到引用计数为0,这个对象就可以销毁了
- (NSUInteger)retainCount
- (void)setName:(NSString *)name{
if (_name != name) {//先判断传进来的是不是新对象
[_name release]; //把_name以前的对象release
_name = [name retain]; //把name对象的地址赋给_name,这时name和_name共同指向同一个对象
}
}
- (void)setName:(NSString *)name{
if (_name != name) {
[_name release];//把_name以前的对象release
_name = [name copy];//把name对象的地址拷贝一份给_name
}
}
-(void)setName:(NSString *)name{
_name = name; //直接赋值
}
ARC是新的LLVM3.0编译器的一项特性,在工程中使用非常简单,不用再写release、retain、autorelease三个关键字。当开启ARC时,编译器
将自动在代码合适的地方插入release、retain和autorelease。
ARC注意点和优点
ARC注意点
ARC优点
ARC的判断原则 只要没有强指针指向对象,对象就会被释放
强指针
//默认所有指针变量都是强指针
Person *p = [[Person alloc]init];
//被_strong修饰的指针
__strong Person *p = [[Person alloc]init];
弱指针(在开发中,千万不要使用一个弱指针保存刚刚创建的对象,会被立即释放)
//被__weak修饰的指针
__weak Person *p = [[Person alloc]init];
由于对象间彼此引用,无法释放,所以,循环引用会引发内存泄漏
@class Animal;
@interface Person : NSObject
@property (nonatomic,strong) Animal *animal;
@end
@class Person;
@interface Animal : NSObject
@property (nonatomic, strong) Person *person;
@end
@class Animal;
@interface Person : NSObject
@property (nonatomic,strong) Animal *animal;
@end
@class Person;
@interface Animal : NSObject
@property (nonatomic, weak) Person *person;
@end
autoreleasepool用于存放那些需要在稍后某个时刻释放的对象,清空自动释放池时,系统会向其中的对象发送release消息
花括号定义了自动释放池的范围,左花括号开始创建,右花括号处自动释放,在此范围的末尾处,括号内的对象回收到release消息
@ autoreleasepool{
}
注:这里只是发送一次release消息,如果当时引用计数不为0,则该对象依然不会释放
autorelease方法会返回对象本身(MRC)
Penson *p = [Person new];
p = [p autorelease];
调用完autorelease 方法后,对象的计数器不变(MRC)
Person *p = [Person new];
p = [p autorelease];
NSLog(@"count= %d",[p retainCount]);//1
autorelease 实际上只是release的调用延迟了,对于每一个autorelease,系统只是把该Object放入了当前的autorelease pool中,当pool 被释放时,该pool中的所有Object会被调用release
//创建一个自动释放池
@autoreleasepool{
Person *p = [[Person alloc]init];
//不用关心对象什么时候释放,只要能够访问p的地方都可以使用p
//只要调用了autorelease,那就不用调用release
p = [p autorelease];
}
//自动释放池销毁了,给自动释放池中所有的对象发送一条release消息
@autoreleasepool{
Person *p =[[[Person alloc]init] autorelease];
}
@autoreleasepool{
Person *p =[[[Person alloc]init] autorelease];
//一万行代码
}
@autoreleasepool{
for (int i= 0;i < 99999; i ++){
//每次调用一次就会创建一个新的对象
//每个对象都会占用一个存储块
Person *p =[[[Person alloc]init] autorelease];
}
}//循环里创建对象会一直在池中,只有执行到这里才会释放
@autoreleasepool{//创建第一个自动释放池
@autoreleasepool{//创建第二个自动释放池
@autoreleasepool{//创建第三个自动释放池
}//销毁第一个自动释放池
}//销毁第二个自动释放池
}//销毁第三个自动释放池
把循环内的代码包裹在autoreleasepool中,那么在循环中自动释放对象就会放在这个池中,这样内存峰值就会降低(内存峰值:app在某个特定的时段内最大内存用量)
for(int i= 0;i < 99999; i ++){
@autoreleasepool{
Person *p =[[Person alloc]init];
[array addObject:p];
}
}