iOS内存管理集合(转)

原文链接

1、讲一下对iOS内存管理的理解

看到这个问题,我准备是从MRC和ARC结合引用计数机制来讲解下内存管理,想到的是比较常规和浅显,更深的原理回答为:(三种方案的结合)

  • TaggedPointer:主要是针对类似于NSNumber的小对象类型
  • NONPOINTER_ISA (64位系统下)
    • 第一位的01代表的是纯isa指针还是NONPOINTER_ISA指针
    • 第二位代码是否有关联对象
    • 第三位代表是否有C++代码
    • 接下来33位代表执行的内存地址
    • 弱引用的标记
    • 是否dealloc的标记等
  • 散列表(包括引用计数表和weak表)
    • SideTables在非嵌入式的64位系统中,有64张SideTable
    • 每一张SideTable主要是由三部分组成,自旋锁引用计数表弱引用表
    • 全局的引用计数之所以不存在同一张表中,是为了避免资源竞争,解决效率问题
    • 引用计数表引入了分离锁的概念,将一张表拆分成多个部分,对他们分别加锁,可以实现并发操作,提高效率

2、使用ARC应该遵循的原则?

  • 不能使用retainreleaseretainCountautorelease
  • 不能使用NSAllocateObjectNSDeallocateObject
  • 不能使用NSZone
  • 不能显示调用dealloc
  • 必须遵守内存管理方法的命名规则
  • 对象性变量不可以作为C语言结构体成员
  • 使用@aotureleasePool来代替NSAutoreleasePool
  • 显示转换idvoid *

3、 ARC自动管理内存的原则

  • 自己生成的对象,自己持有
  • 非自己生成的对象,自己可以持有
  • 自己持有的对象不再需要时,需要对其进行释放
  • 非自己持有的对象不能释放

4、访问__weak修饰的变量,是否已经注册在了@autoreleasePool中?为什么?

__weak修饰符引用的变量属于弱引用,当然已经注册在了@autoreleasePool中,以延长对象的生命周期,否则创建即释放销毁

5、ARCretainCount是怎么存储的?

存在64张哈希表中,根据哈希算法去查找所在的位置,不需要遍历,非常快捷
引用计数表(哈希表): 通过指针的地址,查找到引用计数的地址,大大提升查找效率,通过DisguisedPtr(objc_object)函数存储,同时也通过这个函数查找,避免循环遍历

6、简要说一下@autoreleasePool的数据结构

简单说是双向链表,头尾相接,有parentchild指针
每创建一个释放池,会在首部创建一个哨兵对象,作为标记
最外层释放池的顶端会有一个next指针。当链表的容量满了,就会在链表的顶端,指向下一张表

7、__weak__unsafe_unretain的区别

__weak修饰的指针变量在其引用的对象内存地址销毁后,自动置为nil
__unsafe_unretain不会置为nil,容易出现悬垂指针,发生奔溃,但是效率比__weak

8、ARC情况下,为什么还是需要@autoreleasePool的存在?

避免内存峰值过高,及时释放不需要的内存空间

9、__weak修饰的变量,如何实现在变量没有强引用后自动置为nil?

详细解答
对象的弱引用__weak表也是一张哈希表
__weak修饰符引用的对象地址是key,所有指向这块内存地址的指针会被添加在一个数组里,值为Value,当对象的内存地址销毁后,数组里面所有对象被置为nil

10、说说对strongcopyassignweak__unsafe_unretain__autoreleasing关键词的理解

  • strong:表示修饰的指针强引用指向的对象,使得对象的引用计数加1,该对象只要引用计数不为0就不会被销毁,可以通过将变量强制赋值nil来进行销毁
  • copy:和strong类型,多用于修饰可变类型的不可变对象上,例如NSStringNSArrayNSDictionary
  • assign:主要用来修饰基本数据类型,存储在栈中,无需程序员管理;可以用来修饰对象,但是会出现问题
  • weak:修饰的指针弱引用指针的对象,不持有对象,对象的引用计数不加1,对象销毁时,修饰的指针自动置为nil。用来修饰对象,避免循环引用,不可以修饰基本数据类型。
  • __unsafe_unretain:类似于weak,当时对象被释放后,修饰的指针依然保存着之前的地址,被释放后的地址变为僵尸对象,访问被释放的地址就会出问题,所以是不安全的
  • __autoreleasing:将对象赋值给__autorelease修饰的指针等同于在MRC情况下调用对象的autorelease方法,即将对象添加进自动释放池

11、ARC在编译时做了哪些工作?

根据代码的上下文语境,在合适的位置插入了retainrelease

12、ARC在运行时做了哪些工作?

  • 主要是__weak关键字。修饰的指针引用的对象引用计数为0时自动设置为nil,运行时在工作
  • 为了保证向后兼容性,ARC 在运行时检测到类函数中的 autorelease 后紧跟其后 retain,此时不直接调用对象的 autorelease 方法,而是改为调用 objc_autoreleaseReturnValueobjc_autoreleaseReturnValue 会检视当前方法返回之后即将要执行的那段代码,若那段代码要在返回对象上执行 retain 操作,则设置全局数据结构中的一个标志位,而不执行 autorelease 操作,与之相似,如果方法返回了一个自动释放的对象,而调用方法的代码要保留此对象,那么此时不直接执行 retain ,而是改为执行 objc_retainAoutoreleasedReturnValue函数。此函数要检测刚才提到的标志位,若已经置位,则不执行 retain 操作,设置并检测标志位,要比调用 autoreleaseretain更快。

13、函数返回一个对象时,会对对象autorelease么?为什么?

会,为了延长返回对象的生命周期,给其他使用者留足够的调用时间

14、说一下垂悬指针野指针

  • 垂悬指针:指针指向的内存已经被释放了,但是指针还存在,这是一个悬垂指针或者迷途指针
  • 野指针:没有进行初始化的指针,其实都是野指针

15、属性默认的关键字是什么?

  • MRC:对于对象依次是 atomic,readWrite,retain
  • ARC:对于对象依次是 atomic,readWrite,strong
    如果是基本数据类型,retain/strong变成assign

16、内存中的5大区分别是什么?

  • 栈区:由编译器自动分配管理释放,存放函数的参数值、局部变量的值等,操作方式类似于数据结构中的栈
  • 堆区:一般是由程序分配管理释放,如果程序员不释放,程序结束时可能由OS回收。与数据结构中的堆是两回事,分配方式类似于链表
  • 全局静态区:全局变量和静态变量存储在一起,初始化的全局变量和静态区在一块区域;没有初始化的全局变量和没有初始化的静态变量在相邻的另一块区域,程序结构后由系统释放
  • 常量区:存放的是常量字符串。程序结构后由系统释放
  • 代码区:存放函数体的二进制代码

17、深拷贝和浅拷贝,集合类深拷贝如何实现

  • 深拷贝:内存拷贝,重新开启一块内存区域
  • 浅拷贝:指针拷贝,让目标对象指针和源对象指向同一片内存区域
  • 集合类深拷贝通过归档、解档实现
源对象类型拷贝方式目标对象类型拷贝类型
mutable对象copy不可变深拷贝
mutable对象mutablCopy可变深拷贝
immutable对象copy不可变浅拷贝
immutable对象mutableCopy可变深拷贝

18、BAD_ACCESS在什么情况下出现?

访问了已经被销毁的内存空间,就会报这个错误。根本原因是由悬垂指针没有被释放

19、讲一下@dynamic关键字

@dynamic意味着编译器不会帮助我们自动合成settergetter方法,需要我们手动实现。

20、@autoreleasePool的释放时机?

主要考察的是自动释放池与RunLoop的关系
App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()
第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。
第二个 Observer 监视了两个事件:BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop()_objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observerorder2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: iOS内存管理版本记录如下: 1. iOS 2.0及更早版本:使用手动管理内存的方式。 2. iOS 3.0:引入了基于引用计数的自动内存管理,使用retain和release函数来增加或减少对象的引用计数。 3. iOS 5.0:引入了ARC(自动引用计数)机制,ARC会在编译时自动插入retain和release代码,减少手动管理内存的工作。 4. iOS 7.0:引入了内存诊断工具Memory Usage Report,可以监测App内存使用情况,帮助开发者优化内存管理。 5. iOS 8.0:引入了一些新的API,如NSCache和NSURLSession,使得内存管理更加方便和灵活。 6. iOS 11.0:引入了基于图片大小的UIImage渲染机制,减少了内存占用。 7. iOS 13.0:引入了叫做“Scene”的多任务环境,使得内存管理更加复杂,需要更加小心谨慎地处理内存问题。 总的来说,随着iOS版本的不断更新,内存管理的机制也在不断地完善和优化,使得iOS应用能够更加高效地使用内存,提高用户体验。 ### 回答2: iOS内存管理是由操作系统自动管理的,在不同的版本中有所不同。 在iOS 5之前的版本中,内存管理主要依赖于手动管理引用计数(reference counting)来管理对象的生命周期。开发者需要手动调用retain和release方法来增加或减少对象的引用计数,以确保对象在不再需要时能够被正确释放。这种方式需要开发者非常谨慎地管理对象的引用,以避免内存泄漏或野指针等问题。 从iOS 5开始,iOS引入了自动引用计数(Automatic Reference Counting,ARC)的内存管理机制。ARC可以自动地插入retain、release和autorelease等方法的调用,使得开发者不再需要手动进行内存管理。开发者只需要关注对象的创建和使用,而不需要关心具体的内存管理细节。ARC减少了内存管理的工作量,提高了开发效率,并且减少了内存泄漏和野指针等问题的发生。不过,ARC并不是完全的自动化内存管理,开发者仍然需要遵循一些规则,比如避免循环引用等,以保证内存的正确释放。 随着iOS版本的不断更新,苹果不断改进和优化内存管理机制。每个新版本都带来了更好的性能和更高效的内存管理。开发者可以通过关注苹果的官方文档和开发者社区中的更新内容来了解每个版本中的具体变化和改进。 总结来说,iOS内存管理从手动的引用计数到自动引用计数的演变,极大地简化了开发者的工作,并提高了应用的性能和稳定性。随着不断的改进和优化,iOS内存管理会越来越高效和可靠。 ### 回答3: iOS内存管理版本记录是指苹果公司在不同版本的iOS操作系统中对于内存管理方面的改进和更新记录。随着iOS版本的不断迭代,苹果在内存管理方面进行了一系列的优化和改进,以提高系统的稳定性和性能。 首先,在早期的iOS版本中,苹果采用了手动内存管理的方式,即开发人员需要手动创建和释放内存,容易出现内存泄漏和内存溢出等问题。为了解决这些问题,苹果在iOS5版本中引入了自动引用计数(ARC)机制。ARC机制能够通过编译器自动生成内存管理代码,避免了手动管理内存带来的问题。 其次,iOS6版本引入了内存分页机制。这个机制能够将应用程序内存分成不同的页,将不常用的页置于闲置列表中,从而释放出更多的内存空间。这些闲置列表中的页能够在需要时快速恢复到内存中,减少了内存压力。 此外,iOS7版本中进一步提升了内存管理的能力。苹果在这个版本中引入了内存压缩技术,将内存中的数据进行压缩,从而提高了内存利用率。此外,iOS7还引入了资源清理功能,可以自动清理不再使用的资源,释放内存空间。 最后,在iOS13版本中,苹果进一步改进了内存管理策略。该版本中引入了后台内存优化功能,能够自动优化应用在后台运行时的内存占用,减少了后台应用对于系统内存的占用和影响。 综上所述,iOS内存管理版本记录反映了苹果在不同版本的iOS操作系统中对于内存管理方面的改进和优化。这些改进和优化使得iOS系统更加稳定和高效,并且提升了应用程序的性能和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值