IOS基础知识-内存管理篇

1、ARC的实现原理

ARC的实现过程就是编译器在编译期间对代码在合适的位置上自动加上release和autorelease;遵循的原则如下:
a、对于每一个持有的对象,都会在合适的地方加入release来释放对b象;
b、对于在方法内部创建的对象,都会在方法末尾加入release来释放对象;
c、对于类的对象和实例变量,系统会在dealloc内被释放

2、下面关于Objective-C的内存描述错误的是

A 当使用ARC来管理内存时,代码中不可以出现autorelease
B autoreleasepool 在 drain 的时候会释放在其中分配的对象
C 当使用ARC来管理内存时,在线程中大量分配对象而不用autoreleasepool则可能会造成内存泄露
D 在使用ARC的项目中不能使用NSZone
答案:A;理由:ARC中编译器会在编译期间在合适的位置加上内存管理的代码,只是在我们的源码中看不到而已;

3、如果要在ARC工程中使用MRC,该怎么做?

可以在工程配置文件中添加-fno-objc-arc

4、什么情况下使用weak?与assgin有什么不同?

a、在ARC中,为了避免对象的循环引用,可以用weak来修饰;比如:delegate
b、如果对象已经是强引用了,此时没必要在做抢引用,可以用weak来修饰;比如:IBOutlet
c、weak是ARC中才出现的
d、weak只能修饰OC对象,assgin可以修饰非OC对象
e、weak既不会持有对象,也不会释放对象(与assgin类型);但对象在释放后,weak修饰的会自动设置为nil;而assgin修饰的不会,会变为野指针;

5、调用对象的release方法会销毁吗?

看情况而定,release只是将对象的引用计数-1;如果对象在release之后,内存的引用计数刚好为0,则会调用对象的dealloc方法释放对象;

6、Objective-C对象的内存布局是怎么样的?

先是isa指针,然后是父类的实例变量存放在子类的成员变量之前

7、什么时候需要在程序中创建内存池?如果我们不创建内存池,是否有内存池供我们使用?

用户自己创建的数据线程,需要创建该线程的内存池;
界面线程有自己的内存池

8、autoreleasepool如何实现?

autoreleasepool是基于队列数组实现的;常用的方法:objc_autoreleasepoolPush、objc_autoreleasepoolPop、objc_autorelease

9、Objective-C使用什么机制管理内存

通过内存引用计数器(retainCount)来管理的;当runloop执行完一次,就会坚持对象的引用计数,如果计数刚好为0;则表示该对象不需要使用了,可以释放了;

10、为什么要进行内存管理

因为移动设备的内存空间有限,当程序内存达到一定大小,系统会发出内存警告;当内存达到更大的值,程序会立即崩溃,从而影响用户体验;所以需要进行内存管理

11、内存管理的范围

所有继承自NSObject的对象,对基本数据类型无效;

12、内存管理的原则

a、只要有人在使用对象,那么对象就不会被释放
b、如果你想使用对象,那么就让对象的引用计数+1
c、当你不想使用对象时,就让对象的引用计数-1
d、谁创建、谁释放;比如通过alloc、new、copy创建
e、谁retain,谁release

13、内存管理的研究对象

野指针:对象没有创建或者指向空间地址已经被释放;使用野指针调用对象方法,会导致异常程序崩溃,所以通常在对象release之后,需要把对象的地址清空,置为nil;OC中没有nil异常,调用[nil retain]不会异常
内存溢出:没有配对释放,不符合内存管理法则;提前是赋值nil或者清空,导致release无效
空指针:指针赋值为空nil

14、如何判断对象已经被销毁

重写dealloc方法,对象销毁时,系统胡自动调用,并调用[super dealloc],

15、如果retainCount=0,在使用retain是否可以是对象复活

已经被释放的对象无法复活

16、对象与对象之间的关系

继承关系
组合关系(强包含关系)
依赖关系(对象作为方法的参数)

17、对象组合关系中,如何确保对象不被提前释放?组合关系中的内存泄露有哪些?

在set方法中调用对象的retain方法;
组合关系中的内存泄露:
a、set方法没有retain
b、没有release旧对象
c、set中没有判断传入参数是否是同一个对象

18、正确重写set方法

判断对象是否为同一个
release旧对象
retain新对象

19、分别描述内存管理要点、autorelease、release、NSAutoreleasePool?并说明autorelease是什么时候被release的?简述什么时候由你负责释放对象,什么时候不由你释放?[NSAutoreleasePool release]和[NSAutoreleasePool drain]有什么区别?

内存管理要点: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!

20、自动释放池是什么?是如何工作的?

自动释放池:是存放多个对象类型的指针变量
存入自动释放池的对象,当自动释放池被销毁的时候,会对池内的所有对象进行释放;
可以通过调用对象的autorelease方法,将对象加入到自动释放池
自动释放池的释放是由当前线程的runloop决定的,在runloop迭代结束时释放,之所以可以释放是因为在每个runloop的迭代周期都加入了自动释放池的push和pop
多次调用对象的autorelease,会导致野指针

21、自动释放池何时释放

通过observer监听runloop的状态,一旦runloop进入休眠状态,系统会释放自动释放池

22、ARC通过什么方式帮助开发者管理内存

ARC是在程序编译与运行期间帮助开发者管理内存,由系统自动添加retain、release和autorelease

23、设计一个简单的图片内存缓存器

主要是讲一下常见的缓存算法有:
FIFO(先进先出队列):如果一个数据最早进入队列,则应该最早被移除
  a、新加入的数据插入队列尾部,顺序移动
  b、当需要淘汰数据时,直接移除队列头部的数据
最常见的实现方法就是采用队列Queue来实现,如下图:
1343039394_3810.png
LRU(最近最少使用,淘汰最长时间未使用的对象):如果一个数据最近被访问过,那么将来访问的机率会更高;如下图:
  a、新加入的数据,放在链表的头部
  b、最近使用的数据,移动到链表的头部
  c、当链表满了,移除链表尾部的数据
LRU采用的是双向链表+map的方式实现,之所以采用双向链表,是因为单向链表,如果要删除节点,需要从表头开始变了查找,时间的复杂度为O(n),如果采用双向链表,则可以直接改变节点的前驱指针指向来进行删除;采用map来保存key,value是为了在O(logN)的时间快速找到节点,对应get操作;
1030776-20170111003848666-833030056.jpg
LFU(最不经常使用,淘汰一段时间内使用次数较少的对象):如果一个数据在最近一段时间内使用的次数很少,那么在将来的一段时间被使用的可能性也会很小;如下图:
  a、新加入的数据,插入到队列的尾部
  b、最近使用的数据,引用计数+1,重新排序队列
  c、当需要淘汰数据时,直接删除队列尾部数据
1339235284_4205.png

24、最常出现内存循环引用的场景有哪些?

定时器:当定时器作为某个类的成员变量,而定时器需要指定self为target,这个时候就容易引起循环引用(self->timer->self);如果定时器一直处于validate,则其引用计数一直大于0,所以在使用完定时器之后,需要调用定时器的invalidate方法
block使用:;block在copy的时候会对block里面的对象进行强引用(ARC)或者retainCount+1(非ARC),如果使用不当也容易导致循环引用;最常见的表现就是:某个类将block作为自己的属性变量,然后在block里面又调用的类本身,从而导致循环引用(self->block->self)
delegate:规避代理的循环引用,可以使用assgin(非ARC)和weak(ARC)来修饰delegate解决

25、对象添加到通知中心中,当通知中心发通知时,这个对象却已经被释放了,可能会出现什么问题?

通知是多对多的关系,主要用于跨模块传值;当对象加入到通知中心后,如果在对象被销毁前没有从通知中心移除,当发送通知时就会发生崩溃。所以一定要在对象释放前移除通知

26、ARC下不显式指定任何属性关键字时,默认的关键字都有哪些?

对于基本数据类型,默认关键字是:atomic、readwrite、assgin
对于一般Objective-C的类型,默认关键字是:atomic、readwrite、strong

27、写出下面程序段的输出结果

NSDictionary *dict = [NSDictionary dictionaryWithObject:@"a string value" forKey:@"akey"];
NSLog(@"%@", [dict objectForKey:@"akey"]);
[dict release];
结果:打印出“a string value”的字符串,然后发生崩溃;原因在于利用便利构造器生成的对象,不需要我们手动管理内存,如果手动调用release会造成内存过渡释放

28、请写出以下代码的执行结果

NSString * name = [ [ NSString alloc] init ];
name = @”Habb”;
[ name release];
结论:打印输出结果为“Habb”,在release前后打印都有结果;但是会导致内存泄露,原因在于之前的内存会变成野指针,后面的release不能释放之前创建的内存

29、怎么保证多人开发进行内存泄露的检查

可以使用Analyze静态分析
多人开发最好使用ARC模式来管理内存

30、非自动内存管理情况下怎么做单例模式。

a、声明一个类的静态变量,并置为nil;
b、实现一个类的静态方法,并判断当且仅当类的实例对象为nil时才创建新的实例
c、实现NSCopying协议,实现allocWithZone确保通过alloc、init等方式直接获取实例对象时不会产生另外的对象
d、重写release、autorelease、retain和retainCount方法,以确保单例的状态
e、在多线程环境中,可以使用@synchronized或者GCD来确保静态实例被正确的创建和初始化

31、内存泄露与内存溢出有什么关系?

内存泄露:只一个对象被创建后,没有有效的释放对象,导致对象的内存一直处于占用状态,从而导致内存泄露;长期大量的内存泄露会导致内存溢出

32、[NSArray arrayWithobject:] 这个方法添加对象后,需要对这个数组做释放操作吗?

不需要。因为OC中提供大量的简便构造函数,编译器会在编译阶段自动给加上autorelease,所以这类的内存统一由系统自动管理,不需要手动释放

33、自动释放池的底层实现原理

自动释放池是基于栈实现的,当有新的对象autorelease,会被加入到自动释放池的栈顶;当前线程中每一轮runloop到结束的时候,自动释放池会被释放,然后自动释放池中的所有对象都会被release一次
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355

推荐阅读更多精彩内容

  • 内存管理 简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与a...
    丶逐渐阅读 1,964评论 1 16
  • 内存管理ARC处理原理ARC是Objective-C编译器的特性,而不是运行时特性或者垃圾回收机制,ARC所做的只...
    阳明先生_X自主阅读 336评论 0 3
  • 29.理解引用计数 Objective-C语言使用引用计数来管理内存,也就是说,每个对象都有个可以递增或递减的计数...
    Code_Ninja阅读 1,490评论 1 3
  • 内存管理ARC处理原理ARC是Objective-C编译器的特性,而不是运行时特性或者垃圾回收机制,ARC所做的只...
    阳明先生_X自主阅读 484评论 1 3
  • 内存管理方式 首先明确一点,无论在MRC还是ARC情况下,Objective-C采用的是引用计数式的内存管理方式,...
    软件iOS开发阅读 1,653评论 0 9