转:http://tigercat1977.blog.163.com/blog/static/2141561122012111293337435/
第三讲:Obj-C 内存管理1 - 黄金法则
OC内存管理原理
OC内存管理相对 C/C++ 有何好处
OC内存管理的 alloc, retain, release
遛狗原则
OC 对象生命周期
内存管理 黄金法则
The basic rule to apply is Everything that increases the refernce counter with alloc,
[mutable] copy [Whith Zone:] or retain is charge of the corresponding [auto] release.
如果对一个对象使用了 alloc, [mutable] copy, retain,
那么你必须使用相应的 release 或者 autorelease
内存管理类型定义
基本类型 任何 C 的类型,如:
int, short, char, long, long long, struct, enum, union 等属于基本类型或者结构体
内存管理对于 C 语言基本类型无效
OC类型 (非基本类型)
任何继承于 NSObject 类的对象都属于 OC 类型
也就是除了 C 之外的其他类型
OC 对象结构
C / C++ 内存管理原理
C / C++ 内存管理代码
Int *p1 = malloc(100);
Int *p2 = p1;
Int *p3 = p1;
Free(p2);
Free(p2);
内存管理对象
对于OC的对象,非基本对象(int, short, struct)
NSObject, 凡是继承于 NSObject
每一个对象都有一个 retainCount 计数器。表示当前的被应用的计数器。如果计数为0,那么就真正的释放这个对象
内存管理图示
这就是引用计数的理论。在实际应用中,通过只有两个原因我们才会创建一个对象:
1. 作为一个实例变量保留。
2. 在函数内部作为临时变量使用。
大多数情况下,一个实例变量的设置器(setter)会自动释放(autorelease)
原来引用的对象,同时保留(retain)新的。你只需要保证在 dealloc 函数中释放(release)了它就行了。
遛狗原理
OC内存管理
alloc retain release 函数
alloc 函数是创建对象使用,创建完成后计数器为 1
只用一次
retain 是对一个对象的计数器 +1
可以调用多次
release 是对一个对象计数器 -1
减到 0 对象就会从内存中释放
OC内存管理
Objective - C 类中实现了引用计数器,对象知道当前被引用了次数。
最初对象的计数器是 1 。
如果需要引用对象了,可以给对象发送 release 消息,这样对象计数器就加 1。
当不需要引用对象了,可以给对象发送 release 消息,这样对象计数器就减 1。
当计数器减到 0,自动调用对象的 dealloc 函数,对象就会释放内存。
计数器为 0 的对象不能再使用 release 和其他方法 。
retain / release 例子
NSMutableString *str = [[NSMutableString alloc] init];
// str 计数器为 1
[str retain]; // str 计数器为 2
[str retain]; // str 计数器为 3
[str release]; // str 计数器为 2
[str release]; // str 计数器为 1
[str release]; // str 计数器为 0, 对象释放内存
内存管理总结
Objective - C 的内存管理机制与 .Net / Jave 那种全自动的垃圾回收机制是不同的,它本质上还是 C 语言中的手动管理方式,只不过稍微加了一些自动方式。
Objective - C 的内存管理是基于引用计数的。要做的事情只是关注的引用,而释放内存的工作实际上由运行环境完成。
在最简单的情形中,分配的(alloc)对象,或者是保留(retain)在一些地方的对象,都需要发送一个 release 消息。这也意味着,如果使用了一次 alloc,然后又 retain 了一次,那你需要 release 两次才能释放对象的内存。
下面三种增加对象技术器
1. 当明确的使用 alloc 方法来分配对象。
2. 当明确的使用 copy [WithZone:] 或者 murableCopy[WithZone:] 来 copy 对象时。
3. 当明确使用 retain 消息。
上述三种方法使得计数器增加,那么就需要使用 [auto] release 来明确释放对象,也就是递减计数器。
遛狗原则举例 (一只狗时)这方法不够完善
// Dog.h #import <Foundation/Foundation.h> @interface Dog : NSObject { int _ID; } @property int ID; @end
// Dog.m #import "Dog.h" @implementation Dog @synthesize ID = _ID; - (void) dealloc { NSLog(@"dog %d is dealloc", _ID); [super dealloc]; } @end
// Person.h #import <Foundation/Foundation.h> #import "Dog.h" @interface Person : NSObject { Dog *_dog; } - (void) setDog:(Dog *)aDog; - (Dog *) dog; @end
// Persen.m
@implementation Person - (void) setDog:(Dog *)aDog { if (aDog != _dog) { // _dog = aDog; // [_dog retain]; _dog = [aDog retain]; // 让计数器 +1 } } - (Dog *) dog { return _dog; } - (void) dealloc { NSLog(@"person is delloc"); // 把人拥有的 _dog 释放 [_dog release]; [super dealloc]; } @end
// main.m #import <Foundation/Foundation.h> #import "Dog.h" #import "Person.h" int main (int argc, const char * argv[]) { @autoreleasepool { NSLog(@"Hello, World!"); Dog *dog1 = [[Dog alloc] init]; [dog1 setID:1]; Person *xiaoLi = [[Person alloc] init]; // 小丽要遛狗 [xiaoLi setDog:dog1]; Person *xiaoWang = [[Person alloc] init]; [xiaoWang setDog:dog1]; NSLog(@"dog1 retain count1 is %ld", [dog1 retainCount]); // 输出:dog1 retain count1 is 3 [dog1 release]; NSLog(@"dog1 retain count2 is %ld", [dog1 retainCount]); // 输出:dog1 retain count2 is 2 [xiaoWang release]; NSLog(@"dog1 retain count3 is %ld", [dog1 retainCount]); // 输出:person is delloc // :dog1 retain3 count is 1 [xiaoLi release]; // 输出:person is delloc // :dog 1 is dealloc } return 0; }
// Dog.h #import <Foundation/Foundation.h> @interface Dog : NSObject { int _ID; } @property int ID; @end
// Dog.m #import "Dog.h" @implementation Dog @synthesize ID = _ID; - (void) dealloc { NSLog(@"dog %d is dealloc", _ID); [super dealloc]; } @end
// Person.h #import <Foundation/Foundation.h> #import "Dog.h" @interface Person : NSObject { Dog *_dog; } - (void) setDog:(Dog *)aDog; - (Dog *) dog; @end
// Persen.m
@implementation Person - (void) setDog:(Dog *)aDog { if (aDog != _dog) {
[_dog release]; // 要注意的地方,提前 release _dog = [aDog retain]; // 让计数器 +1 } } - (Dog *) dog { return _dog; } - (void) dealloc { NSLog(@"person is delloc"); // 把人拥有的 _dog 释放 [_dog release]; [super dealloc]; } @end
// main.m #import <Foundation/Foundation.h> #import "Dog.h" #import "Person.h" int main (int argc, const char * argv[]) { @autoreleasepool { Dog *dog1 = [[Dog alloc] init]; [dog1 setID:1]; Dog *dog2 = [[Dog alloc] init]; [dog2 setID:2]; Person *xiaoLi = [[Person alloc] init]; // 小丽要遛狗 [xiaoLi setDog:dog1]; [xiaoLi setDog:dog2]; NSLog(@"dog1 retain count is %ld", [dog1 retainCount]); //输出:dog1 retain count is 1 [dog1 release]; //输出:dog 1 is dealloc NSLog(@"dog2 retain count is %ld", [dog2 retainCount]); //输出:dog2 retain count is 2 [xiaoLi release]; //输出:person is delloc NSLog(@"dog2 retain count is %ld", [dog2 retainCount]); //输出:dog2 retain count is 1 [dog2 release]; //输出:dog 2 is dealloc } return 0; }