ios开发首页投稿(暂停使用,暂停投稿)JC专题

iOS与OS X内存管理

2016-04-20  本文已影响93人  油菜小白
  • 本文的写作目的是为学习记录,同时分享给大家,希望大神能够对文中错误的理解进行指正。

1 相关知识点

1.1 内存管理

软件运行的时候,对计算机内存资源的分配和使用进行管理的策略。

1.2 引用计数

一种内存管理策略。(以下解释来自百度百科)

1.3 iOS与OS X的自动释放池

把所有生成的对象放到一个“池子”里,当超过“池子”的作用域,就会自动帮你释放对象,不用你手动release。

1.4 iOS与OS X的自动引用计数

1.5 内存泄漏

应该让出的内存资源,却一直占着不放。

2 引用计数

3 iOS与OS X的引用计数

3.1 生成对象(alloc/new/copy/mutableCopy)

使用以上方法名称开头,并且以驼峰拼写法命名的方法,也意味着自己生成并持有对象。例如:

allocFirstObject
newSecondObject
copyThirdThat
mutableCopyFourthObject等。

3.2 持有对象(retain)

除去上述的四种方法之外取得的对象,可以用retain方法持有该对象。例如:

id testArr = [NSMutableArray array];
[testArr retain];

3.3 释放对象(release)

自己持有的对象,一旦不再需要,持有者有义务释放该对象。释放使用release方法。例如:

id testObj = [[NSObject alloc] init];
[testObj release];

3.4 废弃对象(dealloc)

当引用计数为0时,则调用dealloc方法废弃对象。
如果需要显示调用dealloc方法,即在废弃对象后进行必要的操作,则需要调用[super dealloc]。例如:

- ( void ) dealloc
{
    [super dealloc];
}

3.5 释放之后再次释放

在持有对象之后,需要释放对象,但不能再次释放已经释放的对象。下例会Crash。例如:

id testObj = [[NSObject alloc] init];
[testObj release];
[testObj release];

3.6 释放自己不持有的对象

非自己生成的对象,需要用retain持有,如果没有用retain持有,就释放也会Crash。例如:

id testObj = [NSMutableArray array];
[testObj release];

4 iOS与OS X的自动释放池autorelease

4.1 具体过程:

例如:

@autoreleasepool {
  Id testObj = [[NSObject alloc] init];
  [testObj autorelease];
}
//也可以通过生成NSAutoreleasePool对象的方式,来生成自动释放池
//通过生成NSAutoreleasePool对象的方式,需要手动废弃自动释放池(使用drain方法)。

4.2 注意事项

5 iOS与OS X的自动引用计数(ARC)

所有ARC的操作需要在Xcode4.2之后进行,并且打开ARC功能(Xcode4.2之后默认打开)。

5.1 变量修饰符

5.1.1 __strong

例如:

{
    id __strong testObj = [[NSObject alloc] init];
    //;在ARC中,以上写法与id testObj = [[NSObject alloc] init]完全相同
}
//超出范围,自动释放

5.1.2 __weak

例如:

@interface Test : NSObject
{
    id __weak testObj;
}
- ( void ) setObject: (id __strong)obj;
@end

@implementation Test
- ( id )init
{
    self = [super init];
}
- ( void ) setObject: (id __strong)obj
{
    testObj = obj;
}

以下为引用:

{
    id test0 = [[Test alloc] init];
    id test1 = [[Test alloc] init];
    [test0 setObject:test1]; 
    [test1 setObject:test0];
    //由于testObj为__weak类型,不持有对象,此处不会发生循环引用
}
//如果testObj为__strong类型,则持有对象
//导致testObj一直持有对象,导致对象无法释放==内存泄漏

5.1.3 __unsafe_unretained

例如:

id __unsafe_unretained testObj1 = nil;
{
    id testObj0 = [[NSObject alloc] init];
    testObj1 = testObj0;
    NSLog(@”%@”,testObj1);
}
NSLog(@”%@”,testObj1);
//其中testObj0的对象引用已被废弃,则访问testObj1有可能出现程序崩溃

5.1.4 __autoreleasing

但也存在个别情况:
1、非自己生成并持有的对象,会自动注册到池中。
例如:

@autoreleasepool {
    id testObj = [NSMutableArray array];
    //生成的对象已自动注册到池中
}

2、访问附有__weak修饰符的变量时,会将即将引用的对象注册到池中。
例如:

@autoreleasepool {
    id testObj0 = [[NSArray alloc] init]; 
    //此处若需将testObj0注册到池中,须显式使用__autoreleasepool修饰符声明

    id __weak testObj1 = testObj0;
    //在赋值的同时,将testObj0引用的对象注册到池中
}

3、id的指针、对象的指针变量会自动附上__autoreleasepool修饰符。
例如:

@autoreleasepool {
    id testObj0 = [[NSObject alloc] init]; // testObj0自动附上__strong修饰符
    id *testObj1 = &testObj0; //*testObj1自动附上__autoreleasepool修饰符
    //此处会报错,因为指针赋值时,修饰符必须一致
}

Tips:无论ARC是否开启,_objc_autoreleasePoolPrint();函数都可以打印出已经注册到当前池中所有对象。

5.2 iOS与OS X中ARC开启的状态下,注意事项

5.2.1 禁用关键字

5.2.2 须遵守的命名规则

5.2.3 不要显示调用dealloc

例如:

- ( void ) dealloc
{
    //无需[super dealloc]
}

5.2.4 不要使用NSAutoreleasePool

在ARC开启的状态下,使用NSAutoreleasePool类生成自动释放池,编译器会报错。

5.2.5 不能使用区域(NSZone)

无论ARC是否开启,最好都不要用(其实我还没去了解这个“区域”是个什么东西o(╯□╰)o)。

5.2.6 对象型变量不能成为struct的成员

例如:

struct TestStruct {
    NSArray * array;
    //报错,不能用对象型变量
}

5.2.7 __bridge转换

例如:

id testObj = [[NSObject alloc] init];
void *testVoid = (__bridge void *)testObj;
id testObj1 = (__bridge id)testVoid;

Tips:Foundation框架与Core Foundation框架的对象互相转换,需要用__bridge关键字进行转换。

5.3 iOS与OS X的属性(property)

属性声明的属性与所有权修饰符的对应关系:

属性声明的属性 所有权修饰符
assign __unsafe_unretained修饰符
copy __strong修饰符(但是赋值的是被复制的对象)
retain __strong修饰符
strong __strong修饰符
unsafe_unretained __unsafe_unretained修饰符
weak __weak修饰符

5.4 容器

5.4.1静态容器(NSArray、NSDictionary、NSSet)

5.4.2 动态容器(NSMutableArray、NSMutableDictionary、NSMutableSet)

1、声明动态容器,需要用指针。
例如:

id __strong *array = nil;

2、附有__strong修饰符的id型变量初始化为nil,附有__strong修饰符的id型指针变量初始化不一定为nil。
3、calloc函数,给附有__strong修饰符的id型指针变量分配内存。
例如:

array = (id __strong *)calloc(entries, sizeof(id));

4、操作__strong修饰符的变量,需要自己释放所有元素。释放所有元素后,利用free(array)的方法废弃内存块。
例如:

for (NSUInteger i = 0; i < entries; ++i) {
    array[i] = nil;
}
free(array);

5、以下函数会造成内存泄漏的危险,请慎用:

6、__weak修饰符与__strong修饰符使用方式相同;但__autoreleasing修饰符存在不可控因素,慎用;__unsafe__unretained修饰符在编译器的内存管理对象之外,只能作为指针类型使用。

参考:

上一篇下一篇

猜你喜欢

热点阅读