使用CADisplayLink、NSTimer有什么注意点?
- 注意内存泄漏、循环引用的问题(self弱引用
timer
会造成内存泄漏,强引用timer
会造成循环引用) - 使用
NSProxy
作为timer
的target
,然后弱引用self
,打破循环引用的问题 -
NSProxy
效率比NSObject
高,专门用来做消息转发的,会省略以下步骤:
1. 去父类寻找方法(本来NSProxy
自身也没其他方法了)
2. 动态方法解析阶段
3. 消息转发的第一步forwardingTargetForSelector
- 最后直接来到消息转发的第二步,执行
methodSignatureForSelector
有返回值再执行forwardInvocation
介绍下内存的几大区域讲一下
- 低地址
- 保留:其他用途,大小由平台决定(32位、64位)
- 代码段(
__TEXT
):编译之后的代码,例如函数 - 数据段(
__DATA
):常量区,比如全局变量、静态变量 - 字符串常量:例如
NSString *str = @"123";
(直接写出来的,不是通过方法创建的那种字符串) - 已初始化数据:例如
static int a = 10;
(定义就赋值的) - 未初始化数据:例如
static int b;
(没赋值的) - 堆
heap
:通过alloc
、malloc
、calloc
等动态分配的空间(实例对象),分配的内存空间地址【越来越大】 - 栈
stack
:函数调用开销,比如局部变量,分配的内存空间地址【越来越小】(先进后出) - 内核区:系统内核相关的区域,只能系统访问,例如让线程休眠的操作
- 高地址
你对 iOS 内存管理的理解
- 使用引用计数来管理OC对象的内存
- 一个新创建的
OC
对象引用计数默认是1,当引用计数减为0,OC
对象就会销毁,释放其占用的内存空间 - 调用
retain
会让OC
对象的引用计数+1,调用release
会让OC
对象的引用计数-1 - 内存管理的经验总结:
- 当调用
alloc
、new
、copy
、mutableCopy
方法返回了一个对象,在不需要这个对象时,要调用release
或者autorelease
来释放它 - 想拥有某个对象,就让它的引用计数+1;不想再拥有某个对象,就让它的引用计数-1
ARC 都帮我们做了什么?
-
ARC
是LLVM编译器
和Runtime系统
相互协助的一个结果
-LLVM
:例如在某个作用域的{}即将结束的时候,自动对里面的对象调用release方法
-Runtime
:例如weak
指针的实现,在程序运行的过程中,监控到对象要销毁时会去清空对象的弱引用
weak指针的实现原理
-
weak
指针会将弱引用存储到一个哈希表(SideTable->weak_table)里面,当对象要销毁时取出这个哈希表,把里面存储的弱引用都清除掉 - 对象调用
dealloc
时会判断isa
的weakly_referenced
是否被弱引用过,有的话会调用clearDeallocating
函数,根据当前对象的地址值通过哈希查找,找到对应的弱引用表,清除里面存储的弱引用
autorelease对象在什么时机会被调用release
- 如果是自定义的
autoreleasepool
,会在自动释放池的{}结束前一刻调用release
- 如果不是在自定义的
autoreleasepool
,而是在main
函数的autoreleasepool
,是由RunLoop
控制的,可能是在某次RunLoop
循环中,在RunLoop
休眠之前调用了release
(kCFRunLoopBeforeWaiting
)
方法里有局部对象, 出了方法后会立即释放吗
-
MRC
环境下不会,会等RunLoop
那次循环的休眠之前才释放 -
ARC
环境下会,LLVM
会在方法的{}即将结束的时候,自动对里面的对象调用release
方法