管理内存有三种方式
1:垃圾回收,在java中常见的管理内存方法,系统自动检测对象是否被使用,是否被释放
2.MRC: 手动管理引用计数,iOS管理内存的方式,程序员通过手动方式来管理对象是否被释放
3.ARC: 自动管理引用计数:基于MRC,系统自动的管理内存
引用计数:retainCount
当我们使用一个指针指向一块内存的时候,应该对这块内存做retain操作,引用计数+1。当我们不再使用这个指针指向这块内存,应该对这块内存做release操作,引用计数-1。这样可以使引用计数值一直保持等于指向这块内存的指针数量。retainCount返回当前内存的引用计数值。当内存被开辟后,默认的引用计数为1 。
注意:内存管理原则 :加多少,对应减多少,加减做到平衡
1.对象被创建出来之后他的引用计数retainCount就变成1
例子:
Boy *boy =[[Boy alloc] init];
NSLog(@"%ld",boy.retainCount);
结果:2015-07-27 19:30:27.587 OC08,09_内存管理[427:8615] 1
2.retain:对对象的引用计数 +1
例子:
Boy *boy =[[Boy alloc] init];
[boy retain];
NSLog(@"%ld",boy.retainCount);
2015-07-27 19:34:35.190 OC08,09_内存管理 [436:9846] 2
3.release :对对象的引用计数进行 -1 的操作
例子:
Boy *boy =[[Boy alloc] init];
[boy retain];
[boy release];
NSLog(@"%ld",boy.retainCount);
2015-07-27 19:36:35.985 OC08,09_内存管理[456:10672] 1
4.当对象的引用计数1 变为 0 的时候,会自动调用dealloc方法,dealloc才是对应对象释放的方法
dealloc在.m文件中实现,dealloc要释放所有不能自己释放的成员变量
例子:
(1)在.h文件中声明三个属性:自定义初始化和便利构造器
@property(nonatomic , retain)NSMutableArray *arr;
@property(nonatomic, copy)NSString *name;
@property(nonatomic, assign)NSInteger age;
-(id)initWithName:(NSString *)name
age:(NSInteger)age;
+(Person *)personWithName:(NSString *)name
age:(NSInteger)age;
在.m文件中完成实现:
-(id)initWithName:(NSString *)name
age:(NSInteger)age{
self =[super init];
if (self) {
self.name=name;
self.age =age;
self.arr=[NSMutableArray array];
}
return self;
}
+(Person *)personWithName:(NSString *)name
age:(NSInteger)age
{
Person *person=[[Person alloc] initWithName:name age:age];
return [person autorelease];
}
在最后需要加一步dealloc:
-(void)dealloc
{
[_arr release];
[_name release];
[super dealloc];
}
实现整个类中的成员变量全部释放,在这里因为age是NSInteger类型,在栈区,系统会自动管理,不需要手动释放
上面这些是完整的声明和实现一个类内的成员变量的方法
注意:
1.当对象调用release引用计数是1时,这个对象就不再对他的引用计数进行 -1 的操作,而是直接调用dealloc方法,所以我们在访问对象的引用计数还是 1
2.如果多次对对象进行释放,会造成过度释放,过度释放也是最常见的内存问题
5.NSString 所定义的字符串它的引用计数是 -1
例子:
NSString *str [email protected]"1111";
NSLog(@"%ld",str.retainCount);
结果:2015-07-27 19:54:12.544 OC08,09_内存管理[495:16187] -1
原因:NSString 的对象在全局静态区,它的引用计数是 -1, 代表整数的最大值,其他的对象如可变字符串.字典等都在堆区,他们在被创建出来的初始引用计数都是 1
6.autorelease:未来的某?时刻引?用计数减1。如果内存之前引?用计 数为4,autorelease之后仍然为4,未来某个时刻会变为3。
release和autorelease的区别:release 马上会把对象的引用计数 -1,但是autorelease会延迟把对象的引用计数 -1
例子:
Boy *boy =[[Boy alloc] init];
[boy retain];
[boy retain];
NSLog(@"%ld",boy.retainCount);
[boy autorelease];
NSLog(@"%ld",boy.retainCount);
结果:
2015-07-27 20:06:16.356 OC08,09_内存管理[541:20376] 3
2015-07-27 20:06:16.357 OC08,09_内存管理[541:20376] 3
7.自动释放池
只要对象用autorelease 释放会把对象放入到系统的自动释放池中,等出了池子的范围,对象引用计数自动 -1,这个相当于java 的垃圾回收,对象释放由系统来管理
例子:
Boy *boy =[[Boy alloc] init];
[boy retain];
[boy retain];
NSLog(@"%ld",boy.retainCount);
@autoreleasepool {
[boy autorelease];
NSLog(@"%ld",boy.retainCount);
}
NSLog(@"%ld",boy.retainCount);
结果:
2015-07-27 20:19:02.918 OC08,09_内存管理[573:23991] 3
2015-07-27 20:19:02.919 OC08,09_内存管理[573:23991] 3
2015-07-27 20:19:02.919 OC08,09_内存管理[573:23991] 2
8.对象的所有权:拥有所有权的对象可以对它进行release——–对象如果是我们进行alloc或者retain之后我们就获取了对象的所有权,就可以对对象进行release;
Boy *b =[Boy boy];
[b retain];
NSLog(@"%ld", b.retainCount);
[b release];
在这里 b 就有了对象的所有权,就可以对对象进行release的操作了
9.遍历构造器在返回对象的时候会加上一个autorelease,所以用便利构造器创建对象不需要对内存进行管理
例子:便利构造器:
+(Boy *)boyWithName:(NSString *)name
hobby:(NSString *)hobby
{
Boy *boy=[[Boy alloc] initWithName:name hobby:hobby];
// 写便利构造器最后别忘了autorelease
return [boy autorelease];
}
10.对象放入容器
(1).当对象放入到容器Array或字典中,对象会被容器进行一次持有,主要是为了防止空指针问题
(2).等对象从容器中移除掉之后,相应地会 -1
例子:
Boy *boy1 =[[Boy alloc] init];
[boy1 retain];
[boy1 retain];
NSLog(@"%ld",boy1.retainCount);
NSMutableArray *arr = [NSMutableArray arrayWithObjects:boy1, nil];
NSLog(@"%ld",[arr[0] retainCount]);
NSLog(@"%ld",boy1.retainCount);
[arr removeObjectAtIndex:0];
NSLog(@"%ld",boy1.retainCount);
结果:
2015-07-27 20:39:49.255 OC08,09_内存管理[608:31455] 3
2015-07-27 20:39:49.256 OC08,09_内存管理[608:31455] 4
2015-07-27 20:39:49.256 OC08,09_内存管理[608:31455] 4
2015-07-27 20:39:49.256 OC08,09_内存管理[608:31455] 3
(3).对象放到数组里,就可以直接释放对象,对象在数组中可以继续使用,直到数组消失时释放对象
例子:
Boy *b=[[Boy alloc] init];
NSArray *arr =@[b];
[b release];
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-07 07:43:04