学习MJ的视频课程,整理总结知识点–weak指针、autorelease原理

引用计数的存储

存储位置
isa

引用计数的存储

对象释放

weak指针的原理

weak引用是存储在哈希表(弱引用表SideTable->weak_table),当对象dealloc时,dealloc方法会清除哈希表中对应的值

关联对象表、引用计数表
dealloc

ARC帮我们做了什么

LLVM+Runtime相互协作的结果
利用LLVM自动帮我们生成release、retain、autorelease等内存管理相关的代码,弱引用的清除利用了Runtime运行时自动处理。

autorelease原理

自动释放池

clang源代码,发现__AtAutoreleasePool的两个关键的函数

runtime中查看这两个函数的实现,发现调用的是AutoreleasePoolPage类的方法

调用了autorelease的对象最终都是通过AutoreleasePoolPage对象来管理的

研究AutoreleasePoolPage的结构

多个pool,之间是通过双向链表联系
知道每个pool内空间的分布

AutoreleasePoolPage的结构

调用push方法会将一个POOL_BOUNDARY入栈(插入边界标记),并且返回其存放的内存地址

调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY

id *next指向了下一个能存放autorelease对象地址的区域

查看的函数
_objc_autoreleasePoolPrint();

push流程,压边界标记,添加autorelease对象到page里

pop流程,查找直到边界标记token,release

autorelease总结

对象存储在AutoreleasePoolPage,每个自动释放池插入自动释放对象前先插入POOL_BOUNDARY作为边界标记

RunLoop与autorelease

autorelease对象在什么时候会被释放
1、被autoreleasepool包围的,出了括号就被释放
2、在iOS项目中测试,并不是被main函数的autoreleasepool管理的,因为main函数里的autoreleasepool包围着主线程的RunLoop,是一直走不到autoreleasepool大括号结尾的

1
2
3
4
5
6
7
8
9
10
11
- (void)viewDidLoad {
[super viewDidLoad];

// 这个Person什么时候调用release,是由RunLoop来控制的
// 它可能是在某次RunLoop循环中,RunLoop休眠之前调用了release
// MJPerson *person = [[[MJPerson alloc] init] autorelease];

MJPerson *person = [[MJPerson alloc] init];

NSLog(@"%s", __func__);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), 1
kCFRunLoopBeforeTimers = (1UL << 1), 2
kCFRunLoopBeforeSources = (1UL << 2), 4
kCFRunLoopBeforeWaiting = (1UL << 5), 32
kCFRunLoopAfterWaiting = (1UL << 6), 64
kCFRunLoopExit = (1UL << 7), 128
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
*/

/*
kCFRunLoopEntry push

<CFRunLoopObserver 0x60000013f220 [0x1031c8c80]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x103376df2), context = <CFArray 0x60000025aa00 [0x1031c8c80]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fd0bf802048>\n)}}


kCFRunLoopBeforeWaiting | kCFRunLoopExit
kCFRunLoopBeforeWaiting pop、push
kCFRunLoopExit pop

<CFRunLoopObserver 0x60000013f0e0 [0x1031c8c80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x103376df2), context = <CFArray 0x60000025aa00 [0x1031c8c80]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fd0bf802048>\n)}}
*/

总结

参考和源码

源码:

评论