2015-02-17 | code

Objective-C 内存管理

目录


##内存管理方式

  • 手动引用计数
  • ARC自动引用计数
  • 垃圾回收

###手动引用计数

Cocoa 环境的 Objective-C 中,每个对象都有一个用来记录引用计数的整数
当某段代码使用到这个对象时就应该将这个整数+1,不需要时-1

使用allocinit创建一个对象后,这个对象的引用计数值为1

1
2
3
4
5
6
7
8
9
10
11
12
//操作引用计数值的方法:
//retainCount 可获取对象的引用计数
//retain 引用计数+1
//release 引用计数-1
//dealloc 释放内存(通常不允许在程序内调用,当引用计数为0时系统会自动发送dealloc消息)
A *a = [[A alloc] init];
printf("retainCount = %d", (int)[a retainCount]);//1
[a retain];
printf("retainCount = %d", (int)[a retainCount]);//2
[a release];
printf("retainCount = %d", (int)[a retainCount]);//1

####自动释放
在代码中经常会使用很多临时对象,如果都要逐个释放内存会很麻烦
可以将所有需要发送release的对象记录下来,再需要释放时统一发送release消息

使用方法如下

1
2
3
4
5
6
7
//NSAutoreleasePool 自动释放池
id pool = [[NSAutoreleasePool alloc] init];
/*
正常的代码操作
向临时对象发送autorelease
*/
[pool release];//自动释放池中所有对象都会销毁

通过alloc init生成的对象需要手动发送autorelease消息
除此之外还有一种创建临时对象的方法,声称对象后会被直接加入内部自动释放池

1
2
3
4
5
6
//以NSString为例
- (id)initWithUTF8String:(const char *) bytes
//生成后引用计数为1
- (id)stringWithUTF8String:(const char *) bytes
//生成后实例对象会被加入自动释放池


###ARC自动引用计数

  • ARC只管理Objective-C 的对象,无法控制malloc分配的内存

  • 禁用和引用计数有关的函数retain,release,autorelease,dealloc

  • ARC是编译期技术,例如:

1
2
3
4
5
6
7
8
9
s = w;

//这刚代码编译后会生成以下代码

[w retain];
id_old = s;
s = w;
[id_old release];

  • 管理自动释放池的新语法
1
2
3
4
@autoreleasepool{
//do something
}
//在非ARC模式下也可以使用 效果比NSAutoReleasePool好
  • 在ARC中未指定初始值的变量都会被初始化为nil

  • ARC中dealloc方法定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//未开启ARC时:
- (void)dealloc {
[xxx release];
if(fp != NULL)
{
fclose(fp);
}
[super dealloc];
}


//ARC有效时
- (void)dealloc {
// [xxx release];
// ARC不能管理的要手动释放
if(fp != NULL)
{
fclose(fp);
}
// 注意!不要调[super dealloc]
// [super dealloc];
}



###循环引用和弱引用

  • 循环引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@interface People : NSObject {

}
@property id friend;
- (void)addFriend:(id)friend;
@end

@implementation People {

}

- (void)addFriend:(id)friend
{
_friend = friend;
}

@end

int main()
{
id a = [[People alloc] init];
id b = [[People alloc] init];

[a addFriend:b];
[b addFriend:a];
}
//是指两个对象a,b分别持有对方的引用,这时实例a因为b持有a的引用
//retainCount != 0 不能被释放。

  • 弱引用
1
2
3
__weak id temp;
//对应的有强引用 未声明weak的默认都是strong
__strong

###ARC的一些限制

  • ARC有效时,不可以在C语言的结构体中定义objc对象

如果一定要使用的话可以加__unsafe_unretained修饰符,这样的话就需要手动管理这部分内存

1
2
3
4
5
struct C {
__unsafe_unretained id a;
__unsafe_unretained NSString *str;

}

###垃圾回收 see