iOS内存管理的问题总结

来源:互联网 发布:沈阳市软件工资 编辑:程序博客网 时间:2024/06/05 08:39

retain/assign/strong/weak/copy的区别

这几个关键字在声明变量的时候经常遇到,那么它们有什么区别,应该如何选择呢?

这些关键字的主要区别,在于对内存的管理。

Objective-C的内存管理机制和引用类别

首先,要介绍一下Objective-C的内存管理机制。Objective-C对内存的管理,以一种叫做“retain count”的方式来管理。对于一个对象,当它被new/alloc/retain的时候,它的retain count会加1;当它被release的时候,它的retain count会减1;当它的retain count达到0的时候,就表示没有其它对象再引用它,这时候编译器会自动调用其dealloc方法,销毁掉这个对象。

另外,对于一个对象,其它对象引用它的方式,有2种方式,一种叫强引用,这个时候retain count会加1;另一种叫弱引用,这个时候retain count不变;这就产生一种结果:对于一个对象A,如果A的强引用都被释放掉了,即使还有其它的弱引用,A的retain count还是会变成0,也就是被销毁掉。这也就是弱引用的“弱”所在。

关键字的区别

有了以上2个概念,就可以区分出以上关键字的区别了。

在MRR(即手动管理内存)阶段,retain表示强引用,assign表示弱引用。用retain修饰的对象,赋值的时候会调用一次retain,将对象的retain count加1;而assign修饰的对象,则直接赋值,retain count不变;

对于int/float等原生的数据类型,可以使用assign;而对于其它需要在多个地方使用的对象,需要用到retain;

iOS5的时候,苹果推出了一个新特性,ARC,这个特性的好处就是编译器会在适当的时候自动添加retain/release/autorelease语句,就避免了人工管理这些代码。简单的理解,strong就是ARC中的retain,而weak就是ARC阶段的assign;

weak和assign的区别

weak和assign很像,它们的区别主要在于:当weak对象指向的内存被释放掉后,它会自动被置为nil,避免了crash;而assign指针在这种情况下会变成野指针,比较危险。

copy关键字

copy关键字比较复杂。在对于不可变类型时,它会和strong一样,拷贝指针;而对于可变类型时,它就会将内容拷贝一份,并指向新的内容。比如:对于NSString,copy的结果和strong一样;而对于NSMutableString,copy就会复制一份出来。

从以上copy的表现来看,可以看出,拷贝的情况有2种:一种是拷贝指针,而指向同一块内存,这种拷贝叫浅拷贝;另外一种,则是将内存拷贝一份,然后指向新的内存,这种拷贝叫深拷贝

强引用导致的retain cycle

强引用会出现一种导致内存泄漏的结果:retain cycle。简单来说,就是A强引用了B,而B也强引用了A。这个时候,A等着B释放A,B也等着A释放B,就会导致A和B都无法释放掉,就造成了内存泄漏。这种情况会在以下情况发生:

  1. 父类/子类之间;
  2. 使用delegate的时候;
  3. 代码块block中。block本身是一个强引用,而且它会建立变量的快照,即强引用处于block里面的变量,这也会导致retain cycle;

如何避免?

对于1和3,可以通过weak关键字,将其中一个引用转成弱引用,这样就打破了retain cycle;

对于2,一般用”__weak”来修饰。很多时候是使用一个weak的self,来防止self类和block形成retain cycle。

注意:UIView的animation block不会导致retain cycle,因为self并没有引用这个block。

最后,对于内存泄漏,如何调试呢?可以用Instruments里的Leak工具来调试,比较方便。