标签:style blog http ar io color os 使用 sp
1.内存管理原理的介绍
1.1C的内存管理
char *p = (char *)malloc(100*sizeof (char));
这是C的动态内存分配,我们手动跟系统申请了100个字节的内存;或者说系统在堆里开辟了100个字节的空间,并将这个空间的首地址返回给指针变量p。
strcpy(p,"Hello World!");
将字符串拷贝给指针变量p指向的内存空间。
puts(p);
将p指针指向的内存空间里的字符串打印出来。
free(p);
使用完成后,手动跟系统释放内存空间;或者说系统回收空间。如上就是C里简单的内存管理。
C的内存管理,我们手动申请,手动释放。
这样来看,我们只需要注意两个问题就好了:
1,申请内存,使用完成后需要释放,如果不释放会造成内存泄漏。
2,不能多次释放,如果多次释放,则会崩溃。
但是,如果项目比较复杂,需要有几十上百号人一起分工完成,就很容易出现问题。
比方说我们开辟了一块内存空间,里面存放了一块很有用的数据。但是,这个数据不只有我在这一块代码里用,甚至有多个人,在程序的多个地方使用。这样造成的结果就是,就算我使用完成这块内存,我也不能去释放他,因为我不能确定,别人在别的地方是否还需要使用这块内存。内存泄露在所难免了。
2.OC的内存管理方式:引用计数
2.1引用计数
对于一块动态申请的内存,有一个人(指针)使用,就给这个内存的计数器(该计数器在该对象中)加1,使用完成后,就给这个计数器减1,当这个内存的引用计数为0了,我们则释放他,这样,上面的问题就解决了。OC,就是使用引用计数这种方式来管理内存的。
2.2内存管理的黄金法则
对于引用计数来说,有一套内存管理的黄金法则:
The basic rule to apply is everything that increases the reference counterwith alloc, [mutable]copy[withZone:] or retain is in charge of the corresponding [auto]release.
如果对一个对象使用了alloc、[mutable]copy、retain,那么你必须使用相应的release或者autorelease。
通俗一点的说法就是谁污染谁治理。
2.3MRC和ARC
ARC Automatic Reference Counting,自动引用计数,由xcode,帮我们去管理内存。
MRC Manual Reference Counting,手动引用计数,由我们手动管理内存。
但就目前来看,很多公司还是使用MRC.
2.4 如何将工程改为MRC
xcode5,工程创建的时候是ARC的,我们如果想要MRC,需要进行如下设置。
选中工程 - >target - >Bulid Settings - >搜索:automatic reference counting或auto,将Objective-C Automatic Reference Counting改为NO。
3.手动内存管理的操作(MRC)
3.1alloc与release
创建一个新的工程,先别将内存管理改为手动
创建一个Dog类
- @interface Dog : NSObject
-
- @end
-
-
-
- @implementation Dog
-
- - (void)dealloc
-
- {
-
- NSLog(@"dog dealloc");
-
- [super dealloc];
-
- }
-
- @end
dealloc里的析构函数,当对象销毁的时候,会自动调用这个方法,我们在这里重写这个方法。
在main函数里,写入如下代码:
- int main(int argc, const charchar * argv[])
-
- {
-
- @autoreleasepool {
-
- Dog *dog = [[Dog alloc] init];
-
- }
-
- NSLog(@"程序即将退出");
-
- return 0;
-
- }
从终端打印信息来看,程序即将退出这条打印之前,已经打印dog dealloc,也就是说在程序运行结束前,dog对象已经销毁了。这个是ARC,由xcode帮我们管理dog对象。
将ARC改为MRC,再执行程序,dog对象并没有销毁,因为我们现在是手动管理了,我们需要遵守内存管理的黄金法则;Dog *dog = [[Dog alloc] init]; 我们需要对dog进行release。
将main函数代码改为如下形式:
- int main(int argc, const charchar * argv[])
-
- {
-
- @autoreleasepool {
-
- Dog *dog = [[Dog alloc] init];
-
- [dog release];
-
- }
-
- NSLog(@"程序即将退出");
-
- return 0;
-
- }
再次执行程序,从打印可以看出,dog对象已经销毁。这就是黄金法则,我们对dog进行alloc,就要对dog进行release。
注意,release 并不是销毁对象,而是让对象的引用计数减1,当对象的引用计数快为0的时候,自动调用dealloc方法并销毁对象。
3.2 retain与retainCount
retain,将对象进项保留操作,也就是使对象的引用计数加1。
retainCount,打印一个对象的引用计数。
将main函数代码改为如下形式:
- int main(int argc, const charchar * argv[])
-
- {
-
- @autoreleasepool {
-
- Dog *dog = [[Dog alloc] init];
-
-
-
- NSLog(@"dog retainCount = %lu",[dog retainCount]);
-
-
-
-
-
-
-
- Dog *dog1 = [dog retain];
-
-
- NSLog(@"dog retainCount = %lu",[dog retainCount]);
-
- Dog *dog2 = [dog retain];
-
-
-
- NSLog(@"dog retainCount = %lu",[dog retainCount]);
-
- NSLog(@"dog1 retainCount = %lu",[dog1 retainCount]);
-
- NSLog(@"dog2 retainCount = %lu",[dog2 retainCount]);
-
-
-
-
-
- [dog release];
-
-
-
-
-
-
- NSLog(@"dog retainCount = %lu",[dog retainCount]);
-
- NSLog(@"dog1 retainCount = %lu",[dog1 retainCount]);
-
- NSLog(@"dog2 retainCount = %lu",[dog2 retainCount]);
-
- [dog1 release];
-
- [dog2 release];
-
-
-
-
-
- Dog *dog = [[Dog alloc] init];
-
- Dog *dog1 = [dog retain];
-
-
-
-
-
-
-
-
- NSLog(@"dog retainCount = %lu",[dog retainCount]);
-
- }
-
- NSLog(@"程序即将退出");
-
- return 0;
-
- }
3.3 类的复合中使用
在上面代码中,增加Person类
- @interface Person : NSObject {
-
-
-
- Dog *_dog;
-
- }
-
- - (void)setDog:(Dog *)dog;
-
- - (Dog *)dog;
-
- @end
setDog方法形式:
- @implementation Person
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - (void)setDog:(Dog *)dog
-
- {
- if (_dog != dog) {
-
- [_dog release];
-
- _dog = [dog retain];
-
- }
- }
-
- - (Dog *)dog
-
- {
- return _dog;
- }
-
- - (void)dealloc
- {
- NSLog(@"person dealloc");
-
-
- [_dog release];
-
- [super dealloc];
-
- }
- @end
错误方法分析:
-
- Dog *xiaoBai = [[Dog alloc] init];
-
- Person *xiaoXin = [[Person alloc] init];
-
- [xiaoXin setDog:xiaoBai];
-
-
-
- NSLog(@"count = %lu",xiaoBai.retainCount);
-
- [xiaoBai release];
-
-
-
- [xiaoXin release];
-
-
-
-
-
- Dog *xiaoBai = [[Dog alloc] init];
-
- Person *xiaoXin = [[Person alloc] init];
-
- [xiaoXin setDog:xiaoBai];
-
-
-
- NSLog(@"count = %lu",xiaoBai.retainCount);
-
- [xiaoBai release];
-
- Dog *xiaoHei = [[Dog alloc] init];
-
- [xiaoXin setDog:xiaoHei];
-
- [xiaoHei release];
-
- [xiaoXin release];
-
-
-
-
-
-
-
- Dog *xiaoBai = [[Dog alloc] init];
-
- Person *xiaoXin = [[Person alloc] init];
-
- [xiaoXin setDog:xiaoBai];
-
-
-
- NSLog(@"count = %lu",xiaoBai.retainCount);
-
- [xiaoBai release];
-
-
-
-
-
- [xiaoXin setDog:xiaoBai];
-
- [xiaoXin release];
-
-
3.4 @property retain,assign,copy展开
i.) retain展开
如上代码里,Person的setter和getter方法,也可以用property,写成如下形式:
@property (nonatomic, retain) Dog *dog;
进行如上测试,都没有问题。
因此,实际如果写成这样@property (nonatomic, retain) Dog *dog;,
则会展开如下:
- - (void)setDog:(Dog *)dog
-
- {
-
- if (_dog != dog) {
-
- [_dog release];
-
- _dog = [dog retain];
-
- }
-
- }
-
-
-
- - (Dog *)dog
-
- {
-
- return _dog;
-
- }
-
-
ii.) assign展开
@property (nonatomic, assign) Dog *dog;,assign是直接复制,
则会展开如下:
- - (void)setDog:(Dog *)dog
-
- {
-
- _dog = dog;
-
- }
-
- - (Dog *)dog
-
- {
-
- return _dog;
-
- }
iii.) copy展开
@property (nonatomic, copy) Dog *dog;,copy,拷贝,
将原来的对象拷贝一份出来,展开如下:
- - (void)setDog:(Dog *)dog
-
- {
-
- if (_dog != dog) {
-
- [_dog release];
-
- _dog = [dog copy];
-
- }
-
- }
-
- - (Dog *)dog
-
- {
-
- return _dog;
-
- }
3.5 字符串内存管理
i.) 字符串的内存管理
对于字符串而言,非常不遵守黄金法则! (如果从字符串的引用计数来看,乱七八糟!)这只是一个表象! 其实内部还是遵循的!!
我们要做的是,我们依旧遵守我们的黄金法则!
- NSString *str = [[NSString alloc] initWithFormat:@"%d %s",1,"hello"];
-
- NSLog(@"count1 = %lu",str.retainCount);
-
- NSString *str2 = @"hello";
-
- NSLog(@"count2 = %lu",str2.retainCount);
-
- NSString *str3 = [str retain];
-
- NSString *str4 = [str2 retain];
-
- NSLog(@"count3 = %lu",str.retainCount);
-
- NSLog(@"count4 = %lu",str2.retainCount);
-
- NSString *str5 = [[NSString alloc] initWithString:str];
-
- NSString *str6 = [[NSString alloc] initWithString:str2];
-
- NSLog(@"count5 = %lu",str5.retainCount);
-
- NSLog(@"count6 = %lu",str6.retainCount);
-
-
-
- [str release];
-
- [str3 release];
-
- [str4 release];
-
- [str5 release];
-
- [str6 release];
-
-
因此,如果是NSString,我们的property格式写成如下: @property (nonatomic, copy) NSString *name;
ii.) copy和mutableCopy
- NSMutableString *string = [[NSMutableString alloc] initWithString:@"hello"];
-
-
-
-
-
-
-
-
-
-
-
-
-
- NSString *string2 = [string copy];
-
- NSLog(@"string2 = %@",string2);
-
-
-
-
-
- NSMutableString *string3 = [string2 mutableCopy];
-
- [string3 appendString:@"world"];
-
- NSLog(@"string3 = %@",string3);
-
-
-
-
-
- [string release];
-
- [string2 release];
-
- [string3 release];
-
-
-
-
3.6 数组的内存管理
- int main(int argc, const charchar * argv[])
-
- {
-
- @autoreleasepool {
-
-
-
- Dog *dog1 = [[Dog alloc] init];
-
- Dog *dog2 = [[Dog alloc] init];
-
- Dog *dog3 = [[Dog alloc] init];
-
- Dog *dog4 = [[Dog alloc] init];
-
- NSLog(@"dog1.retainCount = %lu",dog1.retainCount);
-
- NSMutableArray *array = [NSMutableArray arrayWithObjects:dog1,
-
- dog2, dog3, dog4, nil nil];
-
- NSLog(@"dog1.retainCount = %lu",dog1.retainCount);
-
-
-
- [array addObject:dog1];
-
- NSLog(@"dog1.retainCount = %lu",dog1.retainCount);
-
-
-
-
-
- [array removeLastObject];
-
- NSLog(@"dog1.retainCount = %lu",dog1.retainCount);
-
-
-
-
-
-
-
- NSLog(@"dog1.retainCount = %lu",dog1.retainCount);
-
- [dog1 release];
-
- [dog2 release];
-
- [dog3 release];
-
- [dog4 release];
-
-
-
- }
-
-
-
- return 0;
-
- }
结论
1)当我们创建数组的时候,数组会对每个对象进行引用计数加1
2)当数组销毁的时候,数组会对每个对象进行引用计数减1
3)当我们给数组添加对象的时候,会对对象进行引用计数加1
4)当我们给数组删除对象的时候,会对对象进行引用计数减1
总之,谁污染谁治理,管好自己就可以了。
3.7 autorelease与 autoreleasepool
autoreleasepool是一个对象
autorelease 是一个方法
在main函数里写如下代码:
- int main(int argc, const charchar * argv[])
-
- {
-
- @autoreleasepool {
-
- Dog *dog = [[Dog alloc] init];
-
-
-
- [dog autorelease];
-
-
-
- @autoreleasepool{
-
- [dog autorelease]
-
- }
-
- NSLog(@"retainCount = %lu",dog.retainCount);
-
- }
-
- NSLog(@"程序即将退出");
-
- return 0;
-
- }
注意: autoreleasepool相当于一个数组,如果哪个对象发送autorelease消息,实际将对象的拥有权交给了autoreleasepool;当autoreleasepool销毁的时候,将向autoreleasepool里持有的所有对象都发送一个release消息。
3.8 加方法的内存管理
我们用加方法创建的对象,不用我们release,是因为类内部的实现使用了autorelease,延迟释放。
在Dog类的声明里增加一个加方法
+ (id)dog;
在Dog类的实现里进行实现
+ (id)dog
{
/*注意,这里不要写成release,如果是release,那么刚创建就销毁了,
使用autorelease,使得将对象的拥有权交给了自动释放池,
只要自动释放池没有销毁,dog对象也就不会销毁。*/
return [[[Dog alloc] init] autorelease];
}
在main函数里代码如下:
- int main(int argc, const charchar * argv[])
-
- {
-
- @autoreleasepool {
-
- Dog *dog = [[[Dog alloc] init] autorelease];
-
- Dog *dog1 = [Dog dog];
-
- NSLog(@"count = %lu",dog.retainCount);
-
- NSLog(@"count1 = %lu",dog1.retainCount);
-
- }
-
- }
OC语言--内存管理
标签:style blog http ar io color os 使用 sp
原文地址:http://www.cnblogs.com/yuyanbian/p/4167543.html