OC-内存管理
常用概念
内存泄露
该释放的对象没有释放
iOS程序的内存布局
- 代码段:编译之后的代码
- 数据段
- 字符串常量:比如NSString *str = @”123”
- 已初始化数据:已初始化的全局变量、静态变量等
- 未初始化数据:未初始化的全局变量、静态变量等
- 栈:函数调用开销,比如局部变量。分配的内存空间地址越来越小
- 堆:通过alloc、malloc、calloc等动态分配的空间,分配的内存空间地址越来越大
Tagged Pointer
从64bit开始,iOS引入了Tagged Pointer
技术,用于优化NSNumber
、NSDate
、NSString
等小对象的存储
在没有使用Tagged Pointer
之前, NSNumber
等对象需要动态分配内存
、维护引用计数
等,NSNumber指针存储的是堆中
NSNumber`对象的地址值
使用Tagged Pointer
之后,NSNumber指针里面存储的数据变成了:Tag + Data
,也就是将数据直接存储在了指针中。当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
objc_msgSend
能识别Tagged Pointer
,比如NSNumber
的intValue
方法,直接从指针提取数据,节省了以前的调用开销
如何判断一个指针是否为Tagged Pointer?
iOS平台,最高有效位是1(第64bit);WWDC2020:最低有效位是1
Mac平台,最低有效位是1
OC对象的内存管理
在iOS中,使用引用计数
来管理OC对象的内存.
一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间
调用
retain
会让OC对象的引用计数+1
,调用release
会让OC对象的引用计数-1
想
拥有
某个对象,就让它的引用计数+1
;不
想再拥有某个对象,就让它的引用计数-1
@property
旧:生成一个成员变量,以及setter和getter的声明
,搭配@synthesize
使用
新:生成一个下划线开头成员变量,以及setter和getter的声明
及实现
@synthesize
自动生成成员变量和属性的setter,getter实现
1 | @synthesize dog = _dog; |
@autorelease
系统会在恰当的时候进行释放
可以通过以下私有函数来查看自动释放池的情况
1 | extern void _objc_autoreleasePoolPrint(void); |
拷贝
产生一个副本对象,跟源对象不影响. 修改了源对象,不会影响副本对象;修改了副本对象,不会影响源对象。
iOS提供两种拷贝
- copy 不可变拷贝,产生不可变副本
- mutableCopy,可变拷贝,产生可变副本
深拷贝和浅拷贝
- 浅拷贝:指针拷贝
- 没有产生新对象
- 引用计数+1
- 深拷贝:内容拷贝
- 产生新的对象。
- 新的对象引用计数为1
copy | mutableCopy | |
---|---|---|
NSString | NSString浅拷贝 | NSMutableString深拷贝 |
NSMutableString | NSString深拷贝 | NSMutableString深拷贝 |
NSArray | NSArray浅拷贝 | NSMutableArray |
NSMutableArray | NSArray深拷贝 | NSMutableArray深拷贝 |
NSDictionary | NSDictionary浅拷贝 | NSMutableDictionary深拷贝 |
NSMutableDictionary | NSDictionary深拷贝 | NSMutableDictionary深拷贝 |
copy 并不代表浅拷贝。如果对一个可变对象做copy操作,那么其就是深拷贝。
MRC - 手动内存管理
当调用alloc
、new
、copy
、mutableCopy
方法返回了一个对象,在不需要这个对象时,要调用release
或者autorelease
来释放它
复杂数据类型(retain,strong)的setter和getter
1 | - (void)seDog:(Dog *)dog { |
基础数据类型(assign)的setter和getter
1 | - (void)seAge:(int)age { |
涉及不到内存管理操作
遵循NSCoping协议类型(copy)的setter和getter
1 | - (void)seName:(NSString *)name { |
遍历构造器
譬如[NSArray array]
这种遍历构造器生成的对象,内部做了autorelease
的处理,外部不需要再进行release
操作
集合
copy
在OC中,只有NSData
,NSString
,NSSet
,NSArray
,NSDictionary
这些类支持copy
操作。如果想对其他类实现copy操作,如下代码去实现
遵循NSCoping协议
1 | <NSCoping> |
实现协议方法
1 | - (id)copyWithZone:(NSZone *)zone { |