iOS | 面试 - 内存管理

iOS | 面试知识整理 - 内存管理(五)

1.什么是内存泄漏?

内存泄漏指动态分配内存的对象在使用完后没有被系统回收内存,导致对象始终占有着内存,属于内存管理出错, (例如一个对象或者变量使用完成后没有释放,这个对象一直占用着内存),一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

2. 什么是僵尸对象?

已经被销毁的对象(不能再使用的对象),内存已经被回收的对象。一个引用计数器为0对象被释放后就变为了僵尸对象;

3. 野指针

野指针又叫做'悬挂指针', 野指针出现的原因是因为指针没有赋值,或者指针指向的对象已经释放了, 比如指向僵尸对象;野指针可能会指向一块垃圾内存,给野指针发送消息会导致程序崩溃

比如:

NSObject*obj = [NSObjectnew];[obj release];// obj 指向的内存地址已经释放了,obj 如果再去访问的话就是野指针错误了.野指针错误形式在Xcode中通常表现为:Thread1:EXC_BAD_ACCESS,因为你访问了一块已经不属于你的内存。

4. 什么是空指针?

空指针不同于野指针,他是一个没有指向任何内存的指针,空指针是有效指针,值为nil,NULL,Nil,0等,给空指针发送消息不会报错,不会响应消息;

5. OC对象的内存管理机制?

在iOS中,使用引用计数来管理OC对象的内存

一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间

调用retain会让OC对象的引用计数+1,调用release会让OC对象的引用计数-1

内存管理的经验总结

当调用alloc、new、copy、mutableCopy方法返回了一个对象,在不需要这个对象时,要调用release或者autorelease来释放它

想拥有某个对象,就让它的引用计数+1;不想再拥有某个对象,就让它的引用计数-1

可以通过以下私有函数来查看自动释放池的情况

extern void _objc_autoreleasePoolPrint(void);

6. OC中有GC垃圾回收机制吗?,iPhone上GC吗?

垃圾回收(GC),就是程序中用于处理废弃不用的内存对象的机制,防止内存泄露

OC本身是支持垃圾回头得,不过只支持MAC OSX平台, iOS 平台不支持

7.在OC中与 Alloc 语义相反的是 release 还是 dealloc?

alloc 与 dealloc 语义相反,alloc 是创建变量,dealloc是释放变量

retain 与 release 语义相反, retain 保留一个对象,引用计数器+1, release 使引用计数器 -1;

8.什么是内存溢出?

当程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个int,但给它存了long才能存下的数,那就是内存溢出。

9.内存区域分布

在iOS开发过程中,为了合理的分配有限的内存空间,将内存区域分为五个区,由低地址向高地址分类分别是:代码区、常量区、全局静态区、堆、栈。

代码段 -- 程序编译产生的二进制的数据

常量区 -- 存储常量数据,通常程序结束后由系统自动释放

全局静态区 -- 全局区又可分为未初始化全局区:.bss段和初始化全局区:data段。全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,在程序结束后有系统释放。

堆(heap) -- 程序运行过程中,动态分配的内存

栈(stack) -- 存放局部变量,临时变量

10.堆区和栈取的区别

按管理方式分

对于栈来讲,是由系统编译器自动管理,不需要程序员手动管理

对于堆来讲,释放工作由程序员手动管理,不及时回收容易产生内存泄露

按分配方式分

堆是动态分配和回收内存的,没有静态分配的堆

栈有两种分配方式:静态分配和动态分配

静态分配是系统编译器完成的,比如局部变量的分配

动态分配是有alloc函数进行分配的,但是栈的动态分配和堆是不同的,它的动 态分配也由系统编译器进行释放,不需要程序员手动管理

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

使用Analyze进行代码的静态分析

为避免不必要的麻烦, 多人开发时尽量使用ARC

使用leaks 进行内存泄漏检测

使用一些三方工具

12.block在ARC中和MRC中的用法有什么区别,需要注意什么?

对于没有引用外部变量的Block,无论在ARC还是非ARC下,类型都是NSGlobalBlock,这种类型的block可以理解成一种全局的block,不 需要考虑作用域问题。同时,对他进行Copy或者Retain操作也是无效的

都需要应注意避免循环引用,ARC 下使用__weak 来解决,MRC下使用__Block 来解决;

13.OC 如何对内存管理解决方法?

Objective-C的内存管理主要有三种方式 自动内存管理、手动内存管理、自动释放池。

自动内存计数

手动内存计数:

自动释放池:

14.ARC 都帮我们做了什么?

LLVM + Runtime 会为我们代码自动插入 retain 和 release 以及 autorelease等代码,不需要我们手动管理

15.weak指针的实现原理

Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。

runtime对注册的类, 会进行布局,对于weak对象会放入一个hash表中。 用weak指向的对象内存地址作为key,当此对象的引用计数为0的时候会dealloc,假如weak指向的对象内存地址是a,那么就会以a为键, 在这个weak表中搜索,找到所有以a为键的weak对象,从而设置为nil。

16.方法里有局部对象,出了方法后会立即释放吗

如果是普通的 局部对象 会立即释放

如果是放在了 autoreleasePool 自动释放池,在 runloop 迭代结束的时候释放

17.MRC情况下怎么做单例模式

创建单例设计模式的基本步骤 : ·

声明一个单件对象的静态实例,并初始化为nil。

创建一个类的类工厂方法,当且仅当这个类的实例为nil时生成一个该类 的实例

实现NScopying协议, 覆盖allocWithZone:方法,确保用户在直接分配和 初始化对象时,不会产 生另一个对象。

覆盖release、autorelease、retain、retainCount方法, 以此确保单例的 状态。

在多线程的环境中,注意使用@synchronized关键字或GCD,确保静态实 例被正确的创建和初始化。

18.非OC对象如何管理内存?

非OC对象,其需要手动执行释放操作例:CGImageRelease(ref),否则会造成大量的内存泄漏导致程序崩溃。其他的对于CoreFoundation框架下的某些对象或变量需要手动释放、C语言代码中的malloc等需要对应free。

19. CADisplayLink、NSTimer会出现的问题,以及解决办法?

问题:

CADisplayLink、NSTimer会对target产生强引用,如果target又对它们产生强引用,那么就会引发循环引用

CADisplayLink、NSTimer都是基于 runloop 实现的.runloop 会对 CADisplayLink、NSTimer进行强引用, CADisplayLink、NSTimer又 会对 target 进行引用,造成循环引用

解决方案1.使用block

// 内部使用 WeakSelf,并在视图消失前,关闭定时器__weak__typeof(self)weakSelf =self;NSTimer* timer = [NSTimertimerWithTimeInterval:1repeats:YESblock:^(NSTimer* _Nonnull timer) {NSLog(@"timer");}];self.timer= timer;[[NSRunLoopcurrentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];

解决方案2.使用代理对象(NSProxy)

image.png

.h// 解决循环引用问题@interfaceMyProxy:NSProxy- (instancetype)initWithObjc:(id)objc;+ (instancetype)proxyWithObjc:(id)objc;.m@interfaceMyProxy()@property(nonatomic,weak)idobjc;@end@implementationMyProxy- (instancetype)initWithObjc:(id)objc{self.objc = objc;returnself;}+ (instancetype)proxyWithObjc:(id)objc{return[[selfalloc] initWithObjc:objc];}- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector {return[self.objc methodSignatureForSelector:aSelector];}- (void)forwardInvocation:(NSInvocation*)invocation {if([self.objc respondsToSelector:invocation.selector]) {        [invocation invokeWithTarget:self.objc];    }}

使用方法:

NSTimer* timer = [NSTimertimerWithTimeInterval:1target:[TimerProxy proxyWithTarget:self]                                        selector:@selector(test1)                                        userInfo:nilrepeats:YES];self.timer = timer;[[NSRunLoopcurrentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

20.什么是Tagged Pointer?

从64bit开始,iOS引入了Tagged Pointer技术,用于优化NSNumber、NSDate、NSString等小对象的存储

在没有使用Tagged Pointer之前, NSNumber等对象需要动态分配内存、维护引用计数等,NSNumber指针存储的是堆中NSNumber对象的地址值

使用Tagged Pointer之后,NSNumber指针里面存储的数据变成了:Tag + Data,也就是将数据直接存储在了指针中

当指针不够存储数据时,才会使用动态分配内存的方式来存储数据

21.copy和mutableCopy区别

image.png

22. 内存泄漏可能会出现的几种原因?

第一种可能:第三方框架不当使用;

第二种可能:block循环引用;

第三种可能:delegate循环引用;

第四种可能:NSTimer循环引用

第五种可能:非OC对象内存处理

第六种可能:地图类处理

第七种可能:大次数循环内存暴涨

23. ARC下什么样的对象由 Autoreleasepool 管理

当使用alloc/new/copy/mutableCopy开始的方法进行初始化时,会生成并持有对象(也就是不需要pool管理,系统会自动的帮他在合适位置release),不需要pool进行管理

一般类方法创建的对象需要使用Autoreleasepool进管理

24. 如何实现AutoreleasePool?

AutoreleasePool(自动释放池)其实并没有自身的结构,他是基于多个AutoreleasePoolPage(一个C++类)以双向链表组合起来的结构; 可以通过 push操作添加对象,pod 操作弹出对象,以及通过 release 操作释放对象;

25. AutoreleasePoolPage的结构?以及如何 push 和 pod 的?

image.png

调用push方法会将一个POOL_BOUNDARY入栈,并且返回其存放的内存地址

调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY

id *next指向了下一个能存放autorelease对象地址的区域

26.Autoreleasepool 与 Runloop 的关系

主线程默认为我们开启 Runloop,Runloop 会自动帮我们创建Autoreleasepool,并进行Push、Pop 等操作来进行内存管理

iOS在主线程的Runloop中注册了2个Observer

第1个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush()

第2个Observer 监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()

27.子线程默认不会开启 Runloop,那出现 Autorelease 对象如何处理?不手动处理会内存泄漏吗?

在子线程你创建了 Pool 的话,产生的 Autorelease 对象就会交给 pool 去管理。如果你没有创建 Pool ,但是产生了 Autorelease 对象,就会调用 autoreleaseNoPage 方法。在这个方法中,会自动帮你创建一个 hotpage(hotPage 可以理解为当前正在使用的 AutoreleasePoolPage,如果你还是不理解,可以先看看 Autoreleasepool 的源代码,再来看这个问题 ),并调用 page->add(obj)将对象添加到 AutoreleasePoolPage 的栈中,也就是说你不进行手动的内存管理,也不会内存泄漏啦!StackOverFlow 的作者也说道,这个是 OS X 10.9+和 iOS 7+ 才加入的特性。

28.以下代码会有什么问题吗?

Person *p = [[[[Person alloc]init] autorelease] autorelease];

以上代码会导致程序崩溃,连续调用2次 autorelease,对象被加入自动释放吃2次, 在释放时候,此一次释放对象就已经销毁了,第二次再释放就会崩溃;

29.以下代码运行会有是问题?

dispatch_queue_tqueue = dispatch_get_global_queue(0,0);for(inti=0; i<10000; i++) {dispatch_async(queue, ^{NSString* str = [NSStringstringWithFormat:@"abcdefghijklmn1234566!@#$"];    })}dispatch_queue_tqueue = dispatch_get_global_queue(0,0);for(inti=0; i<10000; i++) {dispatch_async(queue, ^{NSString* str = [NSStringstringWithFormat:@"abc!"];    })}

第一个内存会暴涨,str 会不行的创建,由于是静态方法,会加入到自动释放池,会延迟释放,造成内存暴涨

第二个内存固定,会使用 Tagged Pointer 将值存在地址中

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

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,082评论 1 32
  • 内存管理 简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与a...
    丶逐渐阅读 1,946评论 1 16
  • 内存管理 ARC处理原理 ARC是Objective-C编译器的特性,而不是运行时特性或者垃圾回收机制,ARC所做...
    b485c88ab697阅读 11,180评论 3 47
  • 前言 什么是内存管理?是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效,快速的分配,并且...
    齐滇大圣阅读 31,382评论 8 96
  • 下车 彩虹步道(20分钟) 大树前分组毛毛虫(30分钟) 上厕所(15分钟) 拉圈介绍(四位老师、志愿者)(10分...
    樱桃绘本课阅读 162评论 0 0