1.内存管理的思考原则
(1)自己生成的对象自己持有
(2)非自己生成的对象自己也能持有
(3)不再需要自己持有的对象时释放
(4)非自己持有的对象无法释放
2.Objective-C 方法 alloc/new/copy/mutableCopy 生成并持有对象
retain方法 持有对象
release方法 释放对象
dealloc方法 废弃对象
其中copy方法是基于NSCopying方法约定,由各类实现的copyWithZone方法:方法生成并持有对象的副本,与copy方法类似,mutableCopy方法是基于NSMutableCopying方法约定,由各类实现的mutableCopyWithZone:方法生成并持有对象的副本。两者的区别在于copy生成不可变更的对象,mutableCopy生成可变更的对象
3.autorelease方法功能:是对象在超出指定的生存范围时能够自动并正确的释放(释放时调用release方法)
autolease方法和release方法不同之处在于,release方法立即释放对象,autorelease方法把对象注册到autoreleasepool中,pool结束时自动调用release方法。
4.alloc/retain/release/dealloc 在GNUstep中的实现总结
(1)在Objective-C的对象中存有引用计数这一整数值(苹果实现此处不同)
(2)调用alloc或retain方法后,引用计数值加1
(3)调用release方法后,引用计数减1
(4)引用计数值为0时,调用dealloc方法废弃对象
5.苹果内存管理和引用计数的实现
(1)malloc 和 calloc区别
malloc只负责分配空间,对空间内的内容不做处理,需要memset函数对内存进行赋值
calloc函数分配空间后相应内存空间置0,
(2)GNUstep将引用计数对象保存在占用内存头部的变量中,而苹果的实现则是保存在应用计数表中
通过内存块头部管理引用计数好处如下:
少量代码即可完成
能够统一管理引用计数用内存块与对象用内存块
通过引用计数表管理应用计数好处如下:
对象用内存块分配无需考虑内存块头部
应用计数表各记录中存有内存块地址,可以从各个记录追溯到各对象的内存块
6.ARC所有权修饰符一共有四种(GNUstep实现)
__strong 修饰符
__weak 修饰符
__unsafe_unretained 修饰符
__autoreleasing 修饰符
__strong __weak 和 __autoreleasing 修饰符可以保证附有这些修饰符的自动变量初始化为nil
(1)__strong 修饰符
__strong 修饰符生成并持有对象,retainCount +1,id类型和对象类型的修饰符默认为__strong类型
(2)__weak 修饰符
主要用于解决循环引用问题
__weak 修饰符生成不持有对象,所以能够解决循环引用问题(循环引用容易发生内存泄漏。所谓内存泄漏就是应当废弃的对象超过其生命周期后继续存在)
循环引用:包括类成员变量的循环引用,自引用(对自身的强引用)
__weak修饰符在持有某一个对象的弱引用时。若该对象被废弃,则此弱引用自动失效且处于nil被赋值状态(空弱引用)。通过检查附有__weak修饰符的变量是否为nil,可以判断被赋值的对象是否被已被废弃
访问__weak修饰符的变量时,实际上必定要访问注册到autoreleasepool的对象。
原因:__weak修饰符之持有对象的弱引用,在访问弱引用的过程中,该对象有可能被废弃。如果把要访问的对象注册到autoreleasepool中,那么在@autoreleasepool块结束之前都能确保该对象的存在。因此,在使用附有__weak修饰符的变量时就必定要使用到autoreleasepool中的对象。
(3)__unsafe_unretained 修饰符
不安全的所有权修饰符。ARC式内存管理是编译器的工作,但是附有__unsafe_unretained 修饰符的变量不属于编译器的内存管理对象
__unsafe_unretained 修饰符和__weak修饰符的相同点
如id __unsafe_unretained obj = [[NSObject alloc] init];
上述代码将自己生成并持有的对象赋值给__unsafe_unretained修饰符修饰的变量中,所以obj不持有该对象,所以同__weak修饰符一样生成的对象会立即被释放(或者说随时有可能被释放)
异同点:
__unsafe_unretained 修饰符修饰的变量,超出其作用域释放后并不会置为nil,所以废弃后调用会导致程序崩溃(出现悬垂指针)
(4)__autoreleasing 修饰符
__autoreleasing 修饰符在ARC有效时并不显示调用,
使用@autoreleasepool{
}