当前位置: 首页 > 科技观察

iOS经典面试题总结--内存管理

时间:2023-03-13 01:04:50 科技观察

我根据自己的情况做了一个总结。答案是我的总结。如有不好的回答,望批评指正交流,谢谢!内存管理1.什么是ARC?ARC是automaticreferencecounting自动引用计数,在程序编译时自动添加retain/release。当创建对象时,保留count+1,释放对象时,count-1,当count=0时,销毁对象。在程序中添加autoreleasepool对象,系统会自动添加autorelease方法,如果该对象的引用计数为0,则会被销毁。于是ARC诞生,就是为了解决MRC手动内存管理的一些问题。MRC下内存管理的缺点:释放一块堆内存时,首先要确保所有指向堆空间的指针都已经释放。(避免提前释放)要释放指针指向的堆空间,首先要判断哪些指向同一个堆,这些指针只能释放一次。(避免多次释放,造成内存泄漏)在模块化操作过程中,对象可能被多个模块创建和使用,谁来释放它是不确定的。虽然ARC给我们带来了很多编程,但是也有可能会出现内存泄露的情况。比如下面两种情况:循环引用:A有一个属性引用B,B有一个属性引用A,如果都是强引用,则两个对象都不能释放。死循环:如果一个ViewController中存在***循环,即使ViewController对应的view消失,也无法释放ViewController。2、block一般都是用that关键字修饰的,为什么?块通常装饰有复制键。使用按块复制是MRC遗留下来的“传统”。在MRC中,方法内容的块在栈区。使用copy可以放到堆区。但是你是否在ARC中编写并不重要:编译器会自动复制该块。3、用@property声明的NSString(或NSArray、NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字会出现什么问题?答:使用@property声明NSString、NSArray和NSDictionary。copy关键字经常被使用,因为它们有对应的变量类型:NSMutableString、NSMutableArray和NSMutableDictionary。它们之间可以进行赋值操作。为确保对象中的字符串值不会无意中改变,您应该在设置新的属性值时进行复制。如果我们使用strong,那么这个属性可能指向一个可变对象。如果外部修改可变对象,则会影响此属性。这种特质所表达的从属关系类似于强者。但是,setter方法并不保留新值,而是“复制”它。当属性类型为NSString时,这个trait常用于保护其封装性,因为传递给setter方法的新值可能指向NSMutableString类的一个实例。该类是NSString的子类,代表一个可以修改其值的字符串。如果此时不复制字符串,则在设置属性后,字符串的值可能会在对象不知情的情况下被更改。.因此,这时候就需要复制一个“不可变”(immutable)的字符串,来保证对象中的字符串值不会无意中改变。只要用于实现该属性的对象是“可变的”,它就应该在设置新属性值时制作一个副本。4、runloop、autoreleasepool和线程的关系。每个线程(包括主线程)都有一个Runloop。对于每个Runloop,系统都会隐式创建一个Autoreleasepool,这样所有的releasepool都会形成一个类似callstack的栈结构。在每次Runloop结束时,当前栈顶的Autoreleasepool会被销毁,所以这个EveryObjectinpool会被释放。5.@property的本质是什么?如何生成ivars、getters、setters并将其添加到此类。“属性”有两个概念:ivar(实例变量)、访问方法(accessmethod=getter),即@property=ivar+getter+setter。比如下面的类:@interfaceWBTextView:UITextView@property(nonatomic,copy)NSString*placehold;@property(nonatomic,copy)UIColor*placeholdColor;@endclass定义完属性后,编译器会自动写访问这些attributes方法(autosynthesis),上面代码写的类相当于下面的代码:@interfaceWBTextView:UITextView-(NSString*)placehold;-(void)setPlacehold:(NSString*)placehold;-(UIColor*)placeholdColor;-(void)setPlaceholdColor:(UIColor*)placeholdColor;@end详见:http://blog.csdn.net/jasonjwl/article/details/494273776。写setter方法完成@property(nonatomic,retain)NSString*name和@property(nonatomic,copy)NSString*nameretain属性的setter方法是保留新值释放旧值,然后更新实例变量指向新值。订单很重要。如果在保留新值之前释放旧值,并且两个值指向同一个对象,那么先执行的释放操作可能会导致系统完全回收该对象。-(void)setName:(NSString*)name{[nameretain];[_namerelease];_name=name;}-(void)setName:(NSString*)name{[_namerelease];_name=[namecopy];}7.说说assignvsweak的区别,_blockvs_weakassign适用于基本数据类型,weak适用于NSObject对象,是弱引用。assign其实可以用来修饰对象,为什么不用呢?因为assign修饰的对象被释放后,指针的地址依然存在,也就是说指针没有被置为nil。如果在后续的内存分配中刚刚分配了这个地址,程序就会崩溃。弱修饰对象释放后,指针地址会被置为nil。_block用于修改一个变量,可以在块中修改。_block:用_block修饰的变量会保留在blockcodeblock中(ARC下,MRC不会保留)_weak:用_weak修饰的变量不会保留在blockcodeblock8中。请告知以下代码是否有问题,如果有问题请修改?@autoreleasepool{for(inti=0;i[largeNumber;i++){(由于识别问题,将这行代码中的尖括号替换为方括号)Person*per=[[Personalloc]init];[perautorelease];}}内存管理原则:如果你对一个对象使用了alloc、copy、retain,那么你必须使用相应的release或autorelease。乍一看,这个题目既有alloc又有autorelease,两者搭配起来应该没问题。但是虽然autorelease会将引用计数减一,但它不会立即减一。它的本质功能只是将对象放入最近的自动释放池中。当自动释放池被销毁时,会向自动释放池中的每个对象发送释放消息。这道题的问题在于autorelease。因为largeNumber是一个非常大的数,而autorelease不能立即将引用计数减一,会在循环结束前造成内存溢出问题。解决方法如下:@autoreleasepool{for(inti=0;i[100000;i++){(由于识别问题,将这行代码中的尖括号替换为方括号)@autoreleasepool{Person*per=[[Personalloc]init];[perautorelease];}}}在循环内添加一个自动释放池,这样每一个创建的对象都能及时释放。9、下面的代码有没有问题,如果有问题请修改?@autoreleasepool{NSString*str=[[NSStringalloc]init];[strretain];[strretain];str=@"jxl";[strrelease];[strrelease];[strrelease];}本题同题8存在内存泄漏问题,1.内存泄漏2.指向常量区的对象无法释放。指针变量str本来指向一个开放的堆空间,但是在重新赋值给str之后,str的指针发生了变化,从指向堆空间变成了指向常量区。常量区的变量根本不需要释放,导致原本开辟的堆空间没有释放,导致内存泄漏。10.weak关键字在什么情况下使用,和assign有什么区别?什么时候使用weak关键字?在ARC中,当可能存在循环引用时,往往通过在一端使用weak来解决。比如delegateagent本身已经强引用了,不需要再强引用。这时候也会用到weak,自定义控件属性一般都用weak。差异:weak此特征表示该属性定义了“非拥有关系”。为此类属性设置新值时,setter方法既不会保留新值也不会释放旧值。这个特性和assign一样,但是当属性指向的对象被销毁时,属性值也会被清除。assign的“设置方法”只会对“标量类型”(scalartypes,如CGFloat或NSlnteger等)进行简单的赋值操作。assign可以使用非OC对象,weak必须用于OC对象。11、内存管理语义(assign、strong、weak等的区别)assign“设置方法”只会对“标量”进行简单的赋值操作。strong该属性表示该属性定义了“拥有关系”。当为这样的属性设置新值时,setter首先保留新值,释放旧值,然后设置新值。weak该属性表示该属性定义了“非拥有关系”。为此类属性设置新值时,setter方法既不会保留新值也不会释放旧值。这个trait类似于assign,但是当属性指向的对象被销毁时,属性值也会被清空。unsafe_unretained该trait的语义与assign相同,但适用于“对象类型”。这个特征表达了一种“非拥有关系”。当目标对象被销毁时,属性值不会被自动清除,这与weak的区别。copy这个特质表达的从属关系类似于strong。但是,设置方法不保留新值,设置方法不保留新值,而是“复制”它。当属性类型为NSString*时,这个trait常用于保护其封装性,因为传递给setter方法的新值可能指向NSMutableString类的一个实例。该类是NSString的子类,代表一个可以修改其值的字符串。如果此时不复制字符串,则在设置属性后,字符串的值可能会在对象不知情的情况下被更改。.因此,此时需要复制一个“不可变”的字符串,以保证对象中的字符串值不会无意间改变。只要用于实现该属性的对象是“可变的”,它就应该在设置新属性值时制作一个副本。以后我们会继续增加内存管理和多线程的内容。持续更新中……敬请期待!参考:招聘靠谱的iOS《招聘一个靠谱的iOS》面试题参考答案(上)MattGalloway《Effective Objective-C 2.0》