1.什么是内存泄漏?什么是安全释放?
内存泄露指动态分配内存的对象在使用完后没有被系统回收内存,导致该对象始终占用内存,又无法通过代码访问,属于内存管理出错,如果出现大量内存泄漏,那么会导致系统内存不足的问题。
安全释放指释放掉不再使用的对象的同时不会造成内存泄漏或指针悬挂问题的操作。
2.僵尸对象、野指针、空指针分别指什么?
僵尸对象
一个引用计数为0的OC对象被释放后就变成僵尸对象。僵尸对象的内存已经被系统回收,虽然该对象可能还存在,数据依然在内存中,但僵尸对象已经是不稳定的对象了,不可以再访问或者使用,内存是随时可能被别的对象申请而占用的。需要注意的是,僵尸对象的内存是正常的,不会造成内存泄漏。
野指针
野指针又叫“悬挂指针”,野指针出现的原因是指针没有赋值,或者指针指向的对象已经被释放掉了。野指针指向一块随机的垃圾内存,向它们发送消息会报 EXC_BAD_ACCESS 错误导致程序崩溃。
空指针
空指针不等于野指针,它是一个没有指向任何内容的指针。空指针是有效指针,值为nil、NULL、Nil 或 0 等,给空指针发送消息不会报错,只是不响应消息而已,应该给野指针及时赋予零值使其变成有效的空指针,避免内存报错。
3.OC有GC垃圾回收机制吗?
垃圾回收简单地说就是程序中及时处理废弃不用的内存对象的机制,防止内存中废弃对象堆积过多造成内存泄漏。
OC语言本身是支持垃圾回收机制的,但是有平台局限性,仅限于Mac 桌面系统开发中,而移动设备中是不支持的。
引用计数和垃圾回收是有区别的。垃圾回收是宏观的,对整体进行内存管理,将所有对象看作一个集合,然后在GC循环中定时检测活动对象和非活动对象,及时将用不到的非活动对象释放掉以避免内存泄漏,也就是说用不到的对象就交给GC来管理释放的,而无需开发者关心,典型的是java中的垃圾回收机制。而引用计数是局部的,开发者需要管理每个对象的引用计数,单个对象引用计数为0时就会被马上释放掉。ARC是一种改进,由编译器帮助开发者自动管理引用计数。此外,自动释放池像是一个局部的垃圾回收,将部分垃圾对象集中释放,相对于单个释放,会有一定的延迟。
4.OC中与alloc 语义相反的是 dealloc 还是 release?
alloc 和 dealloc 相反。
retain 和 release 相反。
与alloc 配对使用的方法是release,要从他们的实际效果来看。
实际上,alloc 和 release配对使用只是表象,本质上还是retain 和 release 的配对使用。alloc 用来创建对象,刚创建的对象默认引用计数为1,相当于调用alloc创建对象的过程中同时会调用一次retain使对象引用计数加1,自然要有对应的release的一次调用,使对象不再被使用的时候能够被释放掉防止内存泄漏。
此外,dealloc是对象引用计数为0的时候自动调用的,dealloc没有使对象引用计数减1的作用,只是在对象引用计数为0后被系统进行内存回收的收尾工作。
5.CAAnimation 的 delegate 是强引用还是弱引用?
强引用,1个罕见特例。CAAnimation动画是异步的,如果动画的代理是弱引用而不是强引用,那么会导致其随身都可能被释放掉。在使用动画时要注意采取措施防止循环引用。
CAAnimation代理定义如下
/* The delegate of the animation. This object is retained for the
* lifetime of the animation object. Defaults to nil. See below for the
* supported delegate methods. */
@property(nullable, strong) id <CAAnimationDelegate> delegate;
6.按照默认法则,哪些关键字生成的对象需要手动释放?
使用new、alloc、copy关键字生成的对象和 rattan 了的对象需要手动释放。被设置为 autorelease 的对象不需要手动释放,会直接进入自动释放池。
NSString 的内存管理
OC中创建NSString 字符串的方法主要有以下5种:
// 字面量直接创建
NSString *str1 = @"string";
// 类方法创建
NSString *str2 = [NSString stringWithFormat:@"string"];
// 编译器优化后启用,效果等同于str1的字面量创建方式
NSString *str3 = [NSString stringWithString:@"string"];
// 实例方法创建
NSString *str4 = [[NSString alloc] initWithFormat:@"string"];
// 编译器优化后弃用,效果等同于str1的字面量创建方式
NSString *str5 = [[NSString alloc] initWithString:@"string"];
开发中推荐1和2,最新的编译器优化后废弃了3和5,现在这样会出现警告,说多余,因为实际效果和直接使用字面量创建相同,都是在常量区创建一个不可变字符串,由系统自动管理内存,创建后可以认为被autorelease 了。此外,由于字符串内容都是“string”,使用str1、str3和str5创建的字符串对象实际在常量内存区只有一个备份,这是编译器优化的结果,而str2 和 str4 由于在堆上创建所以自有自己的备份。
此外,str1、str3和str5都是创建的不可变的字符串,位于常量内存区,由系统管理内存。stringWithFormat 和 initWithFormat 创建的是格式化的动态字符串对象,在堆上创建,需要手动管理内存。
7.如果一个对象释放前被加到了 NotificationCenter 中,不在NotificationCenter 中,那么 remove 对象可能会怎样?
只要添加对象到消息中心进行注册,之后就一定要对其remove进行通知注销。将对象添加到消息中心后,消息中心只是保存该对象的地址,消息中心到时候会根据地址发送通知给该对象,但没有取得该对象的强引用,对象引用计数不会加1.如果对象释放后没有从消息中心remove,也就是通知中心还保存着那个指针,而那个指针指向的对象可能已经被销毁了,那么这个指针就称为一个野指针,当通知发生时,会向这个野指针发送消息导致程序崩溃。
网友评论