定时器
下面这种用法会存在内存泄露
#import "ThirdViewController.h"
@interface ThirdViewController ()
@property (nonatomic, strong) CADisplayLink *link;
@end
@implementation ThirdViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//__weak typeof(self) weakSelf = self; 加了这句也不管用
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkTest)];
[link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
self.link = link;
}
- (void)dealloc
{
[self.link invalidate];
}
@end
NSTimer用下面的方式也会引起内存泄露
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(linkTest) userInfo:nil repeats:YES];
self.timer = timer;
}
而使用下面的方式则不会出现内存泄露
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
__weak typeof(self) weakSelf = self;
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
[weakSelf linkTest];
}];
}
内存布局
![](https://img.haomeiwen.com/i1419593/88440386ef34bffc.png)
static变量只有一份,放在数据段区
Tagged Pointer
- 从64bit开始,iOS引入了
Tagged Pointer
技术,用于优化NSNumber、NSDae、NSString等小对象的存储 - 在没有使用Tagged Pointer之前,NSNumber等对象需要动态分配内存、维护引引用计数等,NSNumber指针存储的是堆中NSNumber对象的地址值
- 使用
Tagged Pointe
后,NSNumber指针里面存储的数据变成了:Tag +Data,也就是将数据直接存储在了指针中 - 当对象指针的最低有效位是1,则该指针为Tagged Pointer
- 当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
- objc_msgSend能识别
Tagged Pointer
,比如NSNumber
的intValue
方法,直接从指针提取数据,节省了以前的调用开稍 - 如何判断一个指针是否为Tagged Pointer?
- iOS平台,最高有效位是1(第64bit)
- Mac平台,最低有效位是1
OC对象的内存管理
- 在iOS中,使用引用计数来管理OC对象的内存
- 一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存
- 调用retain会让OC对象的引用计数+1,调用release会让OC对象的引用计数-1
- 内存管理的经验总结
- 当调用alloc、new、copy、mutableCopy方法返回了一个对象,在不需要这个对象时,要调用release释放它
- 想拥有某个对象,就让它的引用计数+1;不想再拥有某个对象,就让它的引用计数-1
- 可以通过以下私有函数来查看自动释放池的情况:
extern void _objc_autoreleasePoolPrint(void);
使用时,先在文件上方声明一下:extern void _objc_autoreleasePoolPrint(void);
,使用时这样即可:_objc_autoreleasePoolPrint()
。
MRC中的set方法
在MRC环境下,正确的 set
方法如下:
- (void)setPerson:(Person *)person
{
if (_person != person)
{
[_person release];
_person = [person retain];
}
}
在MRC环境下常用的内存管理例子如下:
//系统方式
self.array = [NSMutableArray array];
self.array = [[[NSMutableArray alloc]init] autoRelease];
self.array = [[NSMutableArray alloc]init];
[self.array release];
NSMutableArray *array = [[NSMutableArray alloc]init];
self.array = array;
[array release];
或者用下面的方式给自定义对象创建工厂方法:
@interface Person : NSObject
+ (instancetype)person;
@end
@implementation Person
+ (instancetype)person
{
return [[[self alloc]init]autoRelease];
}
@end
synthesis
关键字的用法,@synthesize person = _person
这句话表明生成一个 person
的成员变量,来代替 _person
的变量
在 MRC 环境下,需要在子类的 dealloc
方法里调用父类的 dealloc
方法
copy用法
- 拷贝的目的:产生一个副本对象,跟源对象互不影响
- 修改了源对象,不会影响到副本对象
- 修改了副本对象,不会影响到源对象
iOS提供了2个拷贝方法
- copy,不可变拷贝,产生不可变副本
- mutableCopy,可变拷贝,产生可变副本,都是深拷贝
引用计数的存储
- iOS中,引用计数可以直接存储在优化过的
isa
指针中,也可能存储中SideTable类中 -
extra_rc
里面存储的值是引用计数减1 -
has_sidetable_rc
引用计数器是否过大无法存储在isa
中,如果为1,那么引用计数会存储在一个叫SideTable
的类的属性中。
weak指针的原理
本质上是将弱引用存放在一个散列表中,即哈希表,对象要销毁时,则从表中取出当前对象对应的弱引用表,把表中存储的那些弱引用清除掉。
- ARC都帮我们做了什么?
- LLVM + Runtime相互合作的结果,利用LLVM编译器自动帮我们生成了
release
、autoRelease
和retain
等代码,像弱引用这样的存在则需要运行时Runtime
支持的
- LLVM + Runtime相互合作的结果,利用LLVM编译器自动帮我们生成了
autorelease 原理
- 自动释放池的主要底层数据结构是:__AutoreleasePool、AutoReleasePoolPage
- 调用了
autoRelease
的对象最终都是通过AutoReleasePoolPage
对象来管理的 - 每个
AutoreleasePoolPage
对象占用4096字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease
对象的地址,即一旦对象被调用了autoRelease
方法,则对象的地址会被添加到AutoreleasePoolPage
中 - 所有的
AutoreleasePoolPage
对象通过双向链表的形式连接在一起 - 在开始调用的时候调用了
objc_autoReleasePoolPush
方法,在结束调用的时候调用了objc_autoReleasePoolPop
方法 - 调用push时,会传入
POOLBOUNDARY
并返回一个地址,起到一个标识作用,用来分割不同的@autoreleasepool。 - 调用pop时,会传入end的地址,并从后到前调用对象的
release
方法,直到POOLBOUNDARY
为止。如果存在多个page,会从child的page的最末尾开始调用,直到POOLBOUNDARY。
![](https://img.haomeiwen.com/i1419593/c2aa1fc0edbd2b05.png)
如果是多层@autoreleasepool的嵌套,会用同一个AutoreleasePoolPage对象,以下面的三个嵌套为例,在同一个page中的顺序是下图这样,不同的@autoreleasepool以POOL_BOUNDARY做分割。
![](https://img.haomeiwen.com/i1419593/51df6f0a4f1782ea.png)
网友评论