面试题答案
一键面试1. 引用计数管理方式
- 基本原理:在Objective-C中,每个对象都有一个引用计数(Reference Count,简称RC)。当对象被创建时,引用计数初始化为1。每次有新的指针指向该对象,引用计数加1;当指针不再指向该对象(如指针被释放或重新赋值),引用计数减1。当引用计数降为0时,对象的内存被释放。
- 相关方法:
retain
:发送该消息会使对象的引用计数加1。例如,[obj retain]
,这在手动内存管理(MRC)时代常用。release
:发送该消息会使对象的引用计数减1。如[obj release]
,同样在MRC时代常用。autorelease
:使对象被发送到自动释放池,在自动释放池被排空时,池中的对象会收到release
消息,引用计数减1。
2. 自动释放池工作原理
- 数据结构:自动释放池实际上是一个栈结构。当创建一个自动释放池时,会在栈顶压入一个哨兵对象(objc_autoreleasePoolPush函数)。当对象发送
autorelease
消息时,对象会被添加到栈顶的自动释放池中(放入栈中)。当自动释放池被销毁时(objc_autoreleasePoolPop函数),从栈顶开始向栈底遍历,依次向每个对象发送release
消息,直到遇到哨兵对象。 - 作用时机:在主线程中,系统会在事件循环的适当时间点(例如一次事件处理完成后)自动创建和销毁自动释放池。在子线程中,如果不手动创建自动释放池,对象的自动释放操作可能不会及时执行,导致内存峰值过高。
3. 高并发场景下属性内存管理优化方案
- 方案:使用原子属性(atomic property)和自旋锁。对于属性声明,将其设置为
atomic
,例如@property (nonatomic, strong, atomic) id someProperty;
。原子属性在访问和设置时会使用自旋锁(spinlock)来保证线程安全。自旋锁的原理是当一个线程尝试获取锁时,如果锁已被占用,线程不会立即进入睡眠状态,而是在一定时间内循环尝试获取锁。这样避免了线程上下文切换的开销,在锁被占用时间较短的情况下效率较高。 - 可行性解释:在高并发场景下,多个线程可能同时访问和修改属性。使用原子属性配合自旋锁,可以保证同一时间只有一个线程能访问或修改属性,避免数据竞争和内存管理错误。由于自旋锁在短时间内等待锁时不会导致线程睡眠,减少了线程上下文切换的开销,对于高并发且属性访问时间较短的场景,性能损失相对较小,因此具有可行性。