一、内存管理
1.为什么管理
2.内存管理范围
1>栈:存放局部变量(所占用内存会自动销毁) 2>堆:存放对象(所占用内存需手动销毁) 3>管理范围:所有继承NSObject的类对象
二、引用计数器
1.作用
2.特点
1>当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
2>给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
3>给对象发送一条release消息,可以使引用计数器值-1
4>可以给对象发送retainCount消息获得当前的引用计数器值
// Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
// Person.m
#import "Person.h"
@implementation Person
@end
// main.m
#import "Person.h"
int main(){
/*
Person *p = [Person new];
int count = [p retainCount];
NSLog("count = %d",count); // count = 1
*/
Person *p = [[Person alloc] init];
int count = [p retainCount];
NSLog("count = %d",count); // count = 1
[p retain];
count = [p retainCount];
NSLog("count = %d",count); // count = 2
[p release];
count = [p retainCount];
NSLog("count = %d",count); // count = 1
[p release];
count = [p retainCount];
NSLog("count = %d",count); // count = 0
p = nil;
return 0;
}
3.对象被销毁
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property int age;
@end
// Person.m
#import "Person.h"
@implementation Person
- (void) dealloc
{
NSLog(@"调用 dealloc 方法");
/*
可以在这方法内做一些回收成员变量(如果是OC对象)的操作。
*/
[super dealloc];
}
@end
// main.m
#import "Person.h"
int main(){
Person *p = [[Person alloc] init];
int count = [p retainCount];
NSLog("count = %d",count); // count = 1
[p release]; // 调用 dealloc 方法
count = [p retainCount];
NSLog("count = %d",count); // count = 0
// 操作僵尸对象
// [p setAge:10]; // message sent to deallocated instance
p = nil; // 当对象内存被回收时候,把指针置为空防止野指针出现
return 0;
4.野指针(僵尸对象)
1>如果一个指针指向了一块被回收的内存,那么这个指针成为野指针,一个指针指向一块垃圾内存,如果使用指针来操作被回收的内存后果非常严重 ,被释放内存的OC对象叫僵尸对象。
2>当你用了一个指向不可预知的指针时,即使程序运行没有问题, 那也是非常危险的. 因为这个”野指针”指向的内存空间,可能是某个重要的数据或其它程序,甚至是系统的重要内存位置. 这样造成的危害是不可预知的,这个不可预知包括危害程度的不可预知和危害时间的不可预知的. 像一颗不知何时会爆的定时炸弹。
三、内存管理原则
// Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property int age;
@end
// Person.m
#import "Person.h"
@implementation Person
- (void) dealloc
{
NSLog(@"调用 dealloc 方法");
/*
可以在这方法内做一些回收成员变量(如果是OC对象)的操作。
*/
[super dealloc];
}
@end
// main.m
#import "Person.h"
int main(){
Person *p = [[Person alloc] init];
int count = [p retainCount];
NSLog("count = %d",count); // count = 1
[p release]; // 调用 dealloc 方法
count = [p retainCount];
NSLog("count = %d",count); // count = 0
// 操作僵尸对象
// [p setAge:10]; // message sent to deallocated instance
p = nil; // 当对象内存被回收时候,把指针置为空防止野指针出现
return 0;
}
四、set方法内存管理
- (void)setAge:(int)age
{
_age = age;
}
2>
OC对象类型
- (void)setCar:(Car *)car
{
if ( car != _car) // 1.先判断是不是新传进来的对象
{
[_car release]; // 2.对旧对象做一次release
_car = [car retain]; // 3.对新对象做一次retain
}
}
- (void)dealloc
{
[_car release]; // 一旦Person release,则车也应该release
[super dealloc]; // 这段一定要放最后
}
五、循环引用
1.使用场景
2.循环引用的解决方案
#import <Foundation/Foundation.h>
@class B
@interface A : NSObject
@property (noatomic,assign) B *b; // 对象 B 使用 assign 策略
@end
/*--------------------------------------- A.m ---------------------------------------*/
#import "A.h"
#import "B.h"
@implementation A
- (void) dealloc
{
NSLog(@"调用了对象 A 的 dealloc 方法");
// [_b release]; // 使用 assign 无需release
[super dealloc];
}
@end
/*--------------------------------------- B.h ---------------------------------------*/
#import <Foundation/Foundation.h>
@class A
@interface B : NSObject
@property (noatomic,retain) A *a; // 对象 A 使用 retain 策略
@end
/*--------------------------------------- B.m ---------------------------------------*/
#import "A.h"
#import "B.h"
@implementation B
- (void) dealloc
{
NSLog(@"调用了对象 B 的 dealloc 方法");
[_a release];
[super dealloc];
}
@end
/*--------------------------------------- main.m ---------------------------------------*/
#import "A.h"
#import "B.h"
int main(){
A *a = [[A alloc] init]; // a 的计数器为 1
B *b = [[B alloc] init]; // b 的计数器为 1
[a setB:b]; // 由于使用 assign 策略 b 的计数器为 1
[b setA:a]; // 由于使用 retain 策略 a 的计数器为 1 + 1 = 2
[a release]; // a 的计数器为 2 - 1 = 1
[b release]; // b 的计数器为 1 - 1 = 0
// b 对象回收调用 dealloc 方法 同时 release a
// 输出结果 :
// 调用了对象 B 的 dealloc 方法
// 调用了对象 A 的 dealloc 方法
return 0;
}
六、autorelease
1.作用
2.特点
1>给某个对象发送一条autorelease消息时,就会将这个对象加到一个自动释放池中
2>当自动释放池销毁时,会给池子里面的所有对象发送一条release消息
3>调用autorelease方法时并不会改变对象的计数器,并且会返回对象本身
4>autorelease实际上只是把对release的调用延迟了,对于每一次autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用Release
3.简单的使用
<span style="font-size:12px;">#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
/*--------------------------------------- Person.m ---------------------------------------*/
#import "Person.h"
@implementation Person
- (void) dealloc
{
NSLog(@"调用 dealloc 方法");
[super dealloc];
}
@end
/*--------------------------------------- main.m ---------------------------------------*/
#import "Person.h"
int main(){
@autoreleasepool{
Person *p = [[[Person alloc] init] autorelease];
} // 输出结果 : 调用 dealloc 方法
return 0;
}</span>
注意:
1>ios 5.0后
@autoreleasepool
{
// ....
}
2>ios 5.0前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// .....
[pool release]; // 或[pool drain];