iOS之内存管理浅谈
1.何为ARC
ARC是automatic reference counting自动引用计数,在程序编译时自动加入retain/release。在对象被创建时retain count+1,在对象被release时count-1,当count=0时,销毁对象。程序中加入autoreleasepool对象会由系统自动加 上autorelease方法,如果该对象引用计数为0,则销毁。那么ARC是为了解决MRC手动管理内存存在的一些而诞生的。
MRC下内存管理的缺点:
-
释放一个堆内存时,首先要确定指向这个堆空间的指针都被release了。(避免提前释放)
-
释放指针指向的堆空间,首先要确定哪些指向同一个堆,这些指针只能释放一次。(避免释放多次,造成内存泄露)
-
模块化操作时,对象可能被多个模块创建和使用,不能确定最后由谁释放
-
多线程操作时,不确定哪个线程最后使用完毕。
虽然ARC给我们编程带来的很多好多,但也可能出现内存泄露。如下面两种情况:
-
循环参照:A有个属性参照B,B有个属性参照A,如果都是strong参照的话,两个对象都无法释放。
-
死循环:如果有个ViewController中有无限循环,也会导致即使ViewController对应的view消失了,ViewController也不能释放。
2.block一般用那个关键字修饰,为什么?
block一般使用copy关键之进行修饰,block使用copy是从MRC遗留下来的“传统”,在MRC中,方法内容的block是在栈区的,使用copy可以把它放到堆区。但在ARC中写不写都行:编译器自动对block进行了copy操作。
3.用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?
答: 用@property声明 NSString、NSArray、NSDictionary 经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、 NSMutableDictionary,他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
copy 此特质所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。 当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。这个类 是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。 所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份
4.runloop、autorelease pool以及线程之间的关系。
每个线程(包含主线 程)都有一个Runloop。对于每一个Runloop,系统会隐式创建一个Autorelease pool,这样所有的release pool会构成一个像callstack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object会被release。
5.说说assign 和 weak,__block 和 __weak的区别
assign适用于基本数据类型,weak是适用于NSObject对象,并且是一个弱引用。
assign 其实页可以用来修饰对象,那么为什么不用它呢?因为被assign修饰的对象在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil。如果在 后续内存分配中,刚才分到了这块地址,程序就会崩溃掉。而weak修饰的对象在释放之后,指针地址会被置为nil。
_block是用来修饰一个变量,这个变量就可以在block中被修改。
_block:使用_block修饰的变量在block代码块中会被retain(ARC下,MRC下不会retain)
_weak:使用_weak修饰的变量不会在block代码块中被retain
6.strong,weak,retain,assign的区别
strong和weak是ARC引入的对象变量属性
MRC时期用的是retain和assign
assign:用于非指针变量。用于 基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id 如:
@property (nonatomic, assign) int number;
@property (nonatomic, assign) id className;//id必须用assign
retain:用于指针变量。就是说你定义了一个变量,然后这个变量在程序的运行过程中会被更改,并且影响到其他方法。一般是用于字符串( NSString,NSMutableString),数组(NSMutableArray,NSArray),字典对象,视图对象(UIView ),控制器对象(UIViewController)等
比如:
@property (nonatomic,retain) NSString * myString;
@property (nonatomic, retain) UIView * myView;
@property (nonatomic, retain) UIViewController * myViewController;
strong和weak:
@property(nonatomic,strong) MyClass
*myObject;就是相当于@property(nonatomic,retain) MyClass
*myObject;@property(nonatomic, weak
)id<RNNewsFeedCellDelegate>delegate;就是相当于
@property(nonatomic,assign )id<RNNewsFeedCellDelegate>delegate;
现在系统自动生成的属性都是用weak来修饰的,我想应该是xcode 4.2不支持ARC,所以大家都是用retain。现在xcode4.3支持ARC了,于是苹果建议程序员放弃retain,以后都用weak。
weak 就是相当于assign,同样可以在xcode4.3开发环境下放弃使用assign 使用weak 来代替
7.strong相当于retain,Strong在ARC环境下为默认属性类型。
weak取代之前的assign,对象销毁之后会自动置为nil,防止野指针。
Assign不能自动置为nil,需要手动置为nil.
Delegate基本总是使用weak,以防止循环引用。
assign对基础数据类型(NSInteger,CGFloat)和C数据类型(int,float,double,char等).
Retain用于NSObject及其子类,Retain是指针复制(浅复制),引用计数加1,而不会导致内容被复制。
copy复制内容(深复制)如果调用copy的是数组,则为指针复制(浅复制),仅仅复制子元素的指针。
8.为什么delegate需要用weak修饰?(避免循环引用)
weak
:指明该对象并不负责保持delegate这个对象,delegate这个对象的销毁由外部控制
@property (nonatomic, weak) id<HSDogDelegate>delegate;
strong
:该对象强引用delegate,外界不能销毁delegate对象,会导致循环引用