<h1>1、什么是ARC?(arc是为了解决什么问题诞生的?)</h1>
ARC是Auto Reference Counting的缩写,即自动引用计数。
由编译器在代码合适的位置中自动添加retain/Release/Autorelease/dealloc方法从而进行内存管理.
<h1>3、MRC文件在ARC工程混合编译时,需要在文件的Compiler Flags上添加什么参数</h1>
A -shared
B -fno-objc-arc
C -fobjc-arc
D -dynamic
参考答案:B
<h1>4、什么情况使用 weak 关键字,相比 assign 有什么不同?</h1> 什么情况使用weak关键字?
在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性
自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。
weak与assign的不同?
weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。
assigin 可以用非 OC 对象,而 weak 必须用于 OC 对象
<h1>5、调用对象的release 方法会销毁对象吗?</h1>
不会,调用对象的release 方法只是将对象的引用计数器-1,当对象的引用计数器为0的时候会调用了对象的dealloc 方法才能进行释放对象的内存。
<h1>6、objective-C对象的内存布局是怎样的?</h1>
由于Objective-C中没有多继承,因此其内存布局还是很简单的,就是:最前面有个isa指针,然后父类的实例变量存放在子类的成员变量之前
<h1>7、看下面的程序,第一个NSLog会输出什么?这时str的retainCount是多少?第二个和第三个呢? 为什么?</h1>
NSMutableArray* ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"];
[str retain];
[aryaddObject:str];
NSLog(@”%@%d”,str,[str retainCount]);
[str retain];
[str release];
[str release];
NSLog(@”%@%d”,str,[str retainCount]);
[aryremoveAllObjects]
NSLog(@”%@%d”,str,[str retainCount]);
str的retainCount创建+1,retain+1,加入数组自动+1 3
retain+1,release-1,release-1 2
数组删除所有对象,所有数组内的对象自动-1 1
<h1>8、回答person的retainCount值,并解释为什么</h1>
Person * per = [[Person alloc] init]; 此时person 的retainCount的值是1 self.person = per;
在self.person 时,如果是assign,person的 retainCount的值不变,
仍为1 若是:retain person的retainCount的值加1,变为2
若是:copy person的retainCount值不变,仍为1
<h1>9、什么时候需要在程序中创建内存池?</h1>
用户自己创建的数据线程,则需要创建该线程的内存池
<h1>10、如果我们不创建内存池,是否有内存池提供给我们?</h1>
界面线程维护着自己的内存池,用户自己创建的数据线程,则需要创建该线程的内存池
<h1>11、苹果是如何实现autoreleasepool的?</h1>
autoreleasepool以一个队列数组的形式实现,主要通过下列三个函数完成.
• objc_autoreleasepoolPush
• objc_autoreleasepoolPop
• objc_autorelease
看函数名就可以知道,对autorelease分别执行push、pop操作。销毁对象时执行release操作。
<h1>12、objc使用什么机制管理对象内存?</h1>
通过引用计数器(retainCount)的机制来决定对象是否需要释放。 每次runloop完成一个循环的时候,都会检查对象的 retainCount,如果retainCount为0,说明该对象没有地方需要继续使用了,可以释放掉了。
<h1>13、为什么要进行内存管理?</h1>
因为移动设备的内存极其有限,当一个程序所占内存达到一定值时, 系统会发出内存警告. 当程序达到更大的值时, 程序会闪退, 影响用户体验. 为了保证程序的运行流畅, 必须进行内存管理
<h1>14、内存管理的范围?</h1>
管理所有继承自NSObject的对象, 对基本数据类型无效.是因为对象和其他数据类型在系统中存储的空间不一样,其他局部变量主要存储在栈区(因为基本数据类型占用的存储空间是固定的,一般存放于栈区),而对象存储于堆中,当代码块结束时,这个代码块所涉及到的所有局部变量会自动弹栈清空,指向对象的指针也会被回收,这时对象就没有指针指向,但依然存在于堆内存中,造成内存泄露.
<h1>15、objc使用什么机制管理对象内存(或者内存管理方式有哪些)?(重点)</h1>
1> MRC(manual retain-release)手动内存管理
2> ARC(automatic reference counting)自动引用计数
3> Garbage collection (垃圾回收)。但是iOS不支持垃圾回收, ARC作为LLVM3.0编译器的一项特性, 在iOS5.0 (Xcode4) 版本后推出的。
4> ARC的判断准则, 只要没有强指针指向对象, 对象就会被释放.
<h1>16、iOS是如何管理内存的?</h1>
这个问题的话上一个问题也提到过,讲下block的内存管理,ARC下的黄金法则就行。
这里说下swift里的内存管理:
delgate照样weak修饰,闭包前面用[weak self],swift里的新东西,unowned,举例,如果self在闭包被调用的时候可能为空,则用weak,反之亦然,如果为空时使用了unowned,程序会崩溃,类似访问了悬挂指针,在oc中类似于unsafe_unretained,类似assign修饰了oc对象,对象被销毁后,被unowned修饰的对象不会为空,但是unowned访问速度更快,因为weak需要unwarp后才能使用
<h1>17、对象与对象之间存在的关系</h1>
继承关系
组合关系(是一种强烈的包含关系)
依赖关系(对象作为方法参数传递)
<h1>18、对象的组合关系中,确保成员变量不被提前释放?</h1>
重写set方法,在set方法中,retain该对象。
<h1>19、分别描述内存管理要点、autorelease、release、NSAutoreleasePool?并说明autorelease是什么时候被release的?简述什么时候由你负责释放对象,什么时候不由你释放?[NSAutoreleasePool release]和[NSAutoreleasePool drain]有什么区别?</h1>
内存管理要点:Objective-C 使用引用计数机制(retainCount)来管理内存。
内存每被引用一次,该内存的引用计数+1,每被释放一次引 用计数-1。
当引用计数 = 0 的时候,调用该对象的 dealloc 方法,来彻底从内存中删除该对象。
alloc,allocWithZone,new(带初始化)时:该对象引用计数 +1;
retain:手动为该对象引用计数 +1;
copy:对象引用计数 +1;//注意copy的OC数据类型是否有mutable,如有为深拷贝,新对象计数为1,如果没有,为浅拷贝,计数+1
mutableCopy:生成一个新对象,新对象引用计数为 1;
release:手动为该对象引用计数 -1;
autorelease:把该对象放入自动释放池,当自动释放池释放时,其内的对象引用计数 -1。
NSAutoreleasePool: NSAutoreleasePool是通过接收对象向它发送的autorelease消息,记录该对象的release消息,当自动释放池被销毁时,会自动向池中的对象发送release消息。
autorelease 是在自动释放池被销毁,向池中的对象发送release
只能释放自己拥有的对象。
区别是:在引用计数环境下(在不使用ARC情况下),两者基本一样,在GC(垃圾回收制)环境下,release 是一个no-op(无效操作),所以无论是不是GC都使用drain
面试中内存管理,release和autorelease的含义?这里尤其要强调下autorelease,它引申出自动释放池,也能引申出Run loop!
<h1>20、自动释放池是什么,如何工作 ?</h1>
什么是自动释放池:用来存储多个对象类型的指针变量
自动释放池对池内对象的作用:存入池内的对象,当自动释放池被销毁时,会对池内对象全部做一次release操作
对象如何加入池中:调用对象的autorelease方法
自动释放池能嵌套使用吗:能
自动释放池何时被销毁 :简单的看,autorelease的"}"执行完以后。而实际情况是Autorelease对象是在当前的runloop迭代结束时释放的,
而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop
多次调用对象的autorelease方法会导致:野指针异常
自动释放池的作用:将对象与自动释放池建立关系,池子内调用autorelease,在自动释放池销毁时销毁对象,延迟release销毁时间
<h1>21、自动释放池什么时候释放?</h1>
通过Observer监听RunLoop的状态,一旦监听到RunLoop即将进入睡眠等待状态,就释放自动释放池(kCFRunLoopBeforeWaiting)
<h1>22、IPhone OS有没有垃圾回收?autorelease 和垃圾回收制(gc)有什么关系?</h1>
iOS 中没有垃圾回收。autorelease只是延迟释放,gc是每隔一段时间询问程序,看是否有无指针指向的对象,若有,就将它回收。他们两者没有什么关系。
<h1>23、ARC问题</h1>
什么是arc机制:自动引用计数.
系统判断对象是否销毁的依据:指向对象的强指针是否被销毁
arc的本质:对retainCount计算,创建+1 清空指针 - 1 或者到达autoreleasepool的大括号-1
arc目的:不需要程序员关心retain和release操作.
如何解决arc机制下类的相互引用:.h文件中使用@class关键字声明一个类,两端不能都用强指针,一端用strong一端用weak
<h1>24、ARC通过什么方式帮助开发者管理内存?</h1>
ARC相对于MRC,不是在编译时添加retain/release/autorelease这么简单。应该是编译期和运行期两部分共同帮助开发者管理内存。
1> 在编译期,ARC用的是更底层的C接口实现的retain/release/autorelease,这样做性能更好,也是为什么不能在ARC环境下手动retain/release/autorelease,同时对同一上下文的同一对象的成对retain/release操作进行优化(即忽略掉不必要的操作)
2> ARC也包含运行期组件,这个地方做的优化比较复杂,但也不能被忽略,手动去做未必优化得好,因此直接交给编译器来优化,相信苹果吧!
<h1>25、开发项目时你是怎么检查内存泄露</h1>静态分析 analyze
instruments工具里面有个leak 可以动态分析
如果在block中多次使用 weakSelf的话,可以在block中先使用strongSelf,防止block执行时weakSelf被意外释放对于非ARC,将 **weak 改用为 **block 即可
<h1>26、麻烦你设计个简单的图片内存缓存器(移除策略是一定要说的)</h1>
1> 内存缓存是个通用话题,每个平台都会涉及到。cache算法会影响到整个app的表现。候选人最好能谈下自己都了解哪些cache策略及各自的特点。
2> 常见的有FIFO,LRU,LFU等等。由于NSCache的缓存策略不透明,一些app开发者会选择自己做一套cache机制,其实并不难。
3> FIFO : 新访问的数据插入FIFO队列尾部,数据在FIFO队列中顺序移动;淘汰FIFO队列头部的数据;
4> LRU : 新数据插入到链表头部;每当缓存数据命中,则将数据移到链表头部;当链表满的时候,将链表尾部的数据丢弃;
5> LFU : 新加入数据插入到队列尾部(因为引用计数为1);队列中的数据被访问后,引用计数增加,队列重新排序;当需要淘汰数据时,将已经排序的列表最后的数据块删除;
<h1>27、常见的出现内存循环引用的场景有哪些?</h1>
1> 定时器(NSTimer):NSTimer经常会被作为某个类的成员变量,而NSTimer初始化时要指定self为target,容易造成循环引用(self->timer->self)。 另外,若timer一直处于validate的状态,则其引用计数将始终大于0,因此在不再使用定时器以后,应该先调用invalidate方法
2> block的使用:block在copy时都会对block内部用到的对象进行强引用(ARC)或者retainCount增1(非ARC)。在ARC与非ARC环境下对block使用不当都会引起循环引用问题, 一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,简单说就是self.someBlock =Type var{[self dosomething];或者self.otherVar = XXX;或者_otherVar = …};出现循环的原因是:self->block->self或者self->block->_ivar(成员变量)
3> 代理(delegate):在委托问题上出现循环引用问题已经是老生常谈了,规避该问题的杀手锏也是简单到哭,一字诀:声明delegate时请用assign(MRC)或者weak(ARC),千万别手贱玩一下retain或者strong,毕竟这基本逃不掉循环引用了!
<h1>28、对象添加到通知中心中,当通知中心发通知时,这个对象却已经被释放了,可能会出现什么问题?</h1>
其实这种只是考查对通知的简单应用。通知是多对多的关系,主要使用场景是跨模块传值。当某对象加入到通知中心后,若在对象被销毁前不将该对象从通知中心中移除,当发送通知时,就会造成崩溃。这是很常见的。所以,在添加到通知中心后,一定要在释放前移除。
<h1>29、ARC下不显式指定任何属性关键字时,默认的关键字都有哪些?</h1>
对于基本数据类型默认关键字是:atomic,readwrite,assign
对于普通的Objective-C对象:atomic,readwrite,strong
<h1>30、写一个便利构造器</h1>
+(id)Person {
Person *person=[Person alloc]init];
return [person autorelease]; 备注:ARC时不用 autorelease
}
<h1>31、写出下面程序段的输出结果</h1>
NSDictionary *dict = [NSDictionary dictionaryWithObject:@"a string value" forKey:@"akey"]; NSLog(@"%@", [dict objectForKey:@"akey"]);
[dict release];
打印输出 a string value,然后崩溃----原因:便利构造器创建的对象,之后的release,会造成过度释放
<h1>32、写出方法获取ios内存使用情况?
iOS是如何管理内存的?</h1>
我相信很多人的回答是内存管理的黄金法则,其实如果我是面试官,我想要的答案不是这样的。我希望的回答是工作中如何处理内存管理的。
参考答案:
Block内存管理:由于使用block很容易造成循环引用,因此一定要小心内存管理问题。最好在基类controller下重写dealloc,加一句打印日志,表示类可以得到释放。如果出现无打印信息,说明这个类一直得不到释放,表明很有可能是使用block的地方出现循环引用了。对于block中需要引用外部controller的属性或者成员变量时,一定要使用弱引用,特别是成员变量像_testId这样的,很多人都没有使用弱引用,导致内存得不到释放。
对于普通所创建的对象,因为现在都是ARC项目,所以记住内存管理的黄金法则就可以解决。
<h1>33、很多内置的类,如tableview的delegate的属性是assign不是retain?</h1>
ableview的代理一般都是它所属的控制器,控制器会对它内部的view进行一次retain操作,而tableview对代理控制器也进行一次retain操作,就会出现循环引用问题。
网友评论