iOS:内存管理进阶篇
目录
一,引用计数的存储
二,weak指针的存储
三,autoreleasepool的原理
四,autoreleasepool和runloop的关系
一,引用计数的存储
1,isa
共用体(源码下载地址)
struct objc_object {
isa_t isa;
};
union isa_t {
uintptr_t bits;
struct {
# if __arm64_ // iOS平台
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33;
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19
# elif __x86_64__ // Mac平台
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44;
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8
#endif
};
};
2,SideTable
结构体
struct SideTable {
spinlock_t slock;
RefcountMap refcnts; // 存储引用计数的散列表
weak_table_t weak_table;
};
3,说明
-
从arm64开始,
isa
是一个共用体,里面存储了很多跟对象相关的信息 -
nonpointer
:0表示isa
是普通指针;1表示isa
是共用体 -
extra_rc
:存储的值是对象的引用计数减1 -
has_sidetable_rc
:0表示引用计数存储在extra_rc
中;1表示引用计数存储在SideTable
中(当引用计数过大extra_rc
存储不下时)
4,底层代码
retainCount
inline uintptr_t
objc_object::rootRetainCount()
{
if (isTaggedPointer()) return (uintptr_t)this;
sidetable_lock();
isa_t bits = LoadExclusive(&isa.bits);
ClearExclusive(&isa.bits);
// 如果是共用体
if (bits.nonpointer) {
// 从extra_rc中取出引用计数
uintptr_t rc = 1 + bits.extra_rc;
// 如果存储在SideTable中
if (bits.has_sidetable_rc) {
// 从SideTable中取出引用计数
rc += sidetable_getExtraRC_nolock();
}
sidetable_unlock();
return rc;
}
sidetable_unlock();
return sidetable_retainCount();
}
size_t
objc_object::sidetable_getExtraRC_nolock()
{
assert(isa.nonpointer);
// 取出SideTable
SideTable& table = SideTables()[this];
// 从refcnts中取出引用计数
RefcountMap::iterator it = table.refcnts.find(this);
if (it == table.refcnts.end()) return 0;
else return it->second >> SIDE_TABLE_RC_SHIFT;
}
retain
// 简化代码
ALWAYS_INLINE id
objc_object::rootRetain(bool tryRetain, bool handleOverflow)
{
if (isTaggedPointer()) return (id)this;
do {
transcribeToSideTable = false;
oldisa = LoadExclusive(&isa.bits);
newisa = oldisa;
if (slowpath(!newisa.nonpointer)) {
ClearExclusive(&isa.bits);
if (!tryRetain && sideTableLocked) sidetable_unlock();
if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
// SideTable执行retain
else return sidetable_retain();
}
uintptr_t carry;
// extra_rc中的值+1
newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry); // extra_rc++
} while (slowpath(!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)));
if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
return (id)this;
}
id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
// 取出SideTable
SideTable& table = SideTables()[this];
table.lock();
// 从refcnts中取出引用计数
size_t& refcntStorage = table.refcnts[this];
if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
// 引用计数+1
refcntStorage += SIDE_TABLE_RC_ONE;
}
table.unlock();
return (id)this;
}
release
// 简化代码
ALWAYS_INLINE bool
objc_object::rootRelease(bool performDealloc, bool handleUnderflow)
{
if (isTaggedPointer()) return false;
do {
oldisa = LoadExclusive(&isa.bits);
newisa = oldisa;
if (slowpath(!newisa.nonpointer)) {
ClearExclusive(&isa.bits);
if (sideTableLocked) sidetable_unlock();
// SideTable执行release
return sidetable_release(performDealloc);
}
uintptr_t carry;
// extra_rc中的值-1
newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry); // extra_rc--
if (slowpath(carry)) {
goto underflow;
}
} while (slowpath(!StoreReleaseExclusive(&isa.bits,
oldisa.bits, newisa.bits)));
if (slowpath(sideTableLocked)) sidetable_unlock();
return false;
}
uintptr_t
objc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
// 取出SideTable
SideTable& table = SideTables()[this];
bool do_dealloc = false;
table.lock();
// 从refcnts中取出引用计数
RefcountMap::iterator it = table.refcnts.find(this);
if (it == table.refcnts.end()) {
do_dealloc = true;
table.refcnts[this] = SIDE_TABLE_DEALLOCATING;
} else if (it->second < SIDE_TABLE_DEALLOCATING) {
do_dealloc = true;
it->second |= SIDE_TABLE_DEALLOCATING;
} else if (! (it->second & SIDE_TABLE_RC_PINNED)) {
// 引用计数-1
it->second -= SIDE_TABLE_RC_ONE;
}
table.unlock();
// 如果引用计数为0
if (do_dealloc && performDealloc) {
// 销毁对象
((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);
}
return do_dealloc;
}
二,weak指针的存储
1,底层结构
- 代码
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table; // 存储weak指针的散列表
};
struct weak_table_t {
weak_entry_t *weak_entries; // weak_entry_t数组
size_t num_entries; // 数组元素个数
uintptr_t mask; // 数组长度 - 1
uintptr_t max_hash_displacement; // 最大位移次数
};
// 优先使用静态数组存储,超过4个再使用动态数组存储
#define WEAK_INLINE_COUNT 4 // 静态数组的长度
struct weak_entry_t {
DisguisedPtr<objc_object> referent; // 对象
union {
struct {
weak_referrer_t *referrers; // weak_referrer_t动态数组
uintptr_t out_of_line_ness : 2; // 标识数组是否已创建
uintptr_t num_refs : PTR_MINUS_2; // 数组元素个数
uintptr_t mask; // 数组长度 - 1
uintptr_t max_hash_displacement; // 最大位移次数
};
struct {
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT]; // weak_referrer_t静态数组
};
};
};
- 图解
2,存储
weak_register_no_lock
// 简化代码
id
weak_register_no_lock(weak_table_t *weak_table, id referent_id,
id *referrer_id, bool crashIfDeallocating)
{
// 对象
objc_object *referent = (objc_object *)referent_id;
// weak指针
objc_object **referrer = (objc_object **)referrer_id;
// 在weak_table的weak_entries中查找对象所在的weak_entry_t
weak_entry_t *entry;
if ((entry = weak_entry_for_referent(weak_table, referent))) { // 已找到
// 将weak指针存储到weak_entry_t的数组中
append_referrer(entry, referrer);
}
else { // 未找到(第一次存储)
// 用对象和weak指针新建一个weak_entry_t
weak_entry_t new_entry(referent, referrer);
// 查看weak_table是否需要扩容
weak_grow_maybe(weak_table);
// 将新建的weak_entry_t存储到weak_table的weak_entries中
weak_entry_insert(weak_table, &new_entry);
}
return referent_id;
}
weak_entry_for_referent
static weak_entry_t *
weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
{
assert(referent);
weak_entry_t *weak_entries = weak_table->weak_entries;
if (!weak_entries) return nil;
// 索引 = 对象 & mask
size_t begin = hash_pointer(referent) & weak_table->mask;
size_t index = begin;
size_t hash_displacement = 0;
// 从索引对应的位置开始循环查找,直到对象相等为止
while (weak_table->weak_entries[index].referent != referent) {
index = (index+1) & weak_table->mask;
if (index == begin) bad_weak_table(weak_table->weak_entries);
hash_displacement++;
// 循环次数 > 最大位移次数
if (hash_displacement > weak_table->max_hash_displacement) {
return nil; // 未找到
}
}
// 已找到
return &weak_table->weak_entries[index];
}
append_referrer
static void append_referrer(weak_entry_t *entry, objc_object **new_referrer)
{
if (! entry->out_of_line()) { // 如果动态数组未创建
for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
// 如果静态数组还有空间
if (entry->inline_referrers[i] == nil) {
// 将weak指针存储到静态数组中
entry->inline_referrers[i] = new_referrer;
return;
}
}
// 如果静态数组已满,就创建长度为4的动态数组
weak_referrer_t *new_referrers = (weak_referrer_t *)
calloc(WEAK_INLINE_COUNT, sizeof(weak_referrer_t));
// 将静态数组中存储的weak指针转移到动态数组中
for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
new_referrers[i] = entry->inline_referrers[i];
}
entry->referrers = new_referrers;
entry->num_refs = WEAK_INLINE_COUNT;
entry->out_of_line_ness = REFERRERS_OUT_OF_LINE;
entry->mask = WEAK_INLINE_COUNT-1;
entry->max_hash_displacement = 0;
}
assert(entry->out_of_line()); // 动态数组已创建才能往下执行
// 如果动态数组中元素个数大于或等于动态数组长度的3/4
if (entry->num_refs >= TABLE_SIZE(entry) * 3/4) {
// 将动态数组扩容至2倍并将weak指针存储进去
return grow_refs_and_insert(entry, new_referrer);
}
// 索引 = weak指针 & mask
size_t begin = w_hash_pointer(new_referrer) & (entry->mask);
size_t index = begin;
size_t hash_displacement = 0;
// 从索引对应的位置开始循环查找,直到有空位置为止
while (entry->referrers[index] != nil) {
hash_displacement++;
index = (index+1) & entry->mask;
if (index == begin) bad_weak_table(entry);
}
if (hash_displacement > entry->max_hash_displacement) {
entry->max_hash_displacement = hash_displacement;
}
// 将weak指针存储到动态数组中
weak_referrer_t &ref = entry->referrers[index];
ref = new_referrer;
entry->num_refs++;
}
3,移除
weak_unregister_no_lock
void
weak_unregister_no_lock(weak_table_t *weak_table, id referent_id,
id *referrer_id)
{
// 对象
objc_object *referent = (objc_object *)referent_id;
// weak指针
objc_object **referrer = (objc_object **)referrer_id;
weak_entry_t *entry;
if (!referent) return;
// 在weak_table的weak_entries中查找对象所在的weak_entry_t
if ((entry = weak_entry_for_referent(weak_table, referent))) {
// 将weak指针从weak_entry_t的数组中移除
remove_referrer(entry, referrer);
bool empty = true;
// 如果动态数组中还有元素
if (entry->out_of_line() && entry->num_refs != 0) {
empty = false;
}
else { // 如果静态数组中还有元素
for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
if (entry->inline_referrers[i]) {
empty = false;
break;
}
}
}
// 如果静态数组和动态数组中都没有元素
if (empty) {
// 从weak_table的weak_entries中移除weak_entry_t
weak_entry_remove(weak_table, entry);
}
}
}
remove_referrer
static void remove_referrer(weak_entry_t *entry, objc_object **old_referrer)
{
// 如果动态数组未创建
if (! entry->out_of_line()) {
// 将weak指针从静态数组中移除
for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
if (entry->inline_referrers[i] == old_referrer) {
entry->inline_referrers[i] = nil;
return;
}
}
objc_weak_error();
return;
}
// 索引 = weak指针 & mask
size_t begin = w_hash_pointer(old_referrer) & (entry->mask);
size_t index = begin;
size_t hash_displacement = 0;
// 从索引对应的位置开始循环查找,直到找到weak指针为止
while (entry->referrers[index] != old_referrer) {
index = (index+1) & entry->mask;
if (index == begin) bad_weak_table(entry);
hash_displacement++;
if (hash_displacement > entry->max_hash_displacement) {
objc_weak_error();
return;
}
}
// 将weak指针从动态数组中移除
entry->referrers[index] = nil;
entry->num_refs--;
}
4,对象销毁时将weak
指针置为nil
void
weak_clear_no_lock(weak_table_t *weak_table, id referent_id)
{
// 对象
objc_object *referent = (objc_object *)referent_id;
// 在weak_table的weak_entries中查找对象所在的weak_entry_t
weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
if (entry == nil) {
return;
}
weak_referrer_t *referrers;
size_t count;
// 如果动态数组已创建
if (entry->out_of_line()) {
// 取出动态数组
referrers = entry->referrers;
count = TABLE_SIZE(entry);
}
else { // 如果动态数组未创建
// 取出静态数组
referrers = entry->inline_referrers;
count = WEAK_INLINE_COUNT;
}
// 将数组中的weak指针都置为nil
for (size_t i = 0; i < count; ++i) {
objc_object **referrer = referrers[i];
if (referrer) {
if (*referrer == referent) {
*referrer = nil;
}
else if (*referrer) {
objc_weak_error();
}
}
}
// 从weak_table的weak_entries中移除weak_entry_t
weak_entry_remove(weak_table, entry);
}
三,autoreleasepool的原理
1,__AtAutoreleasePool
结构体
- 实例代码
int main(int argc, char * argv[]) {
@autoreleasepool {
YJPerson *person = [[[YJPerson alloc] init] autorelease];
}
return 0;
}
- 底层代码(用
clang
进行转换)
struct __AtAutoreleasePool {
__AtAutoreleasePool() { // 构造函数
atautoreleasepoolobj = objc_autoreleasePoolPush();
}
~__AtAutoreleasePool() { // 析构函数
objc_autoreleasePoolPop(atautoreleasepoolobj);
}
void * atautoreleasepoolobj;
};
int main(int argc, char * argv[]) {
{
__AtAutoreleasePool __autoreleasepool; // 调用构造函数(初始化)
YJPerson *person = ((YJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((YJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((YJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("YJPerson"),
sel_registerName("alloc")), sel_registerName("init")), sel_registerName("autorelease"));
} // 调用析构函数(已超出作用域)
return 0;
}
- 转换代码
int main(int argc, char * argv[]) {
// @autoreleasepool {
atautoreleasepoolobj = objc_autoreleasePoolPush();
YJPerson *person = [[[YJPerson alloc] init] autorelease];
objc_autoreleasePoolPop(atautoreleasepoolobj);
// }
}
-
objc_autoreleasePoolPush
和objc_autoreleasePoolPop
函数
void *
objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void
objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
2,AutoreleasePoolPage
类
- 说明
1>调用
autorelease
方法的对象都是通过AutoreleasePoolPage
对象来管理的2>每个
AutoreleasePoolPage
对象占用4096个字节,它内部的成员变量占56个字节,剩下的4040个字节用来存储autorelease
对象3>如果一个
AutoreleasePoolPage
对象存储不下,系统会创建第二个AutoreleasePoolPage
对象,依次类推,它们通过双向链表的形式连接在一起
- 结构
// 假设AutoreleasePoolPage对象的内存地址为0x1000
class AutoreleasePoolPage
{
magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
// 存储autorelease对象的起始位置
id * begin() {
return (id *) ((uint8_t *)this+sizeof(*this)); // 0x1000 + 56(0x0038)= 0x1038
}
// 存储autorelease对象的结束位置
id * end() {
return (id *) ((uint8_t *)this+SIZE); // 0x1000 + 4096(0x1000)= 0x2000
}
}
- 图解
3,存储和释放
- 实例代码
int main(int argc, char * argv[]) {
@autoreleasepool { // b1 = push()
YJPerson *person1 = [[[YJPerson alloc] init] autorelease];
YJPerson *person2 = [[[YJPerson alloc] init] autorelease];
@autoreleasepool { // b2 = push()
YJPerson *person3 = [[[YJPerson alloc] init] autorelease];
YJPerson *person4 = [[[YJPerson alloc] init] autorelease];
@autoreleasepool { // b3 = push()
YJPerson *person5 = [[[YJPerson alloc] init] autorelease];
YJPerson *person6 = [[[YJPerson alloc] init] autorelease];
} // pop(b3)
} // pop(b2)
} // pop(b1)
return 0;
}
- 三次
push
的结果
- 三次
pop
的过程
- 说明
1>
push
函数会将POOL_BOUNDARY
存储到AutoreleasePoolPage
对象中,用来标记当前@autoreleasepool
的边界2>调用
autorelease
方法的对象会存储到AutoreleasePoolPage
对象中3>
pop
函数会依次释放autorelease
对象,直到遇到POOL_BOUNDARY
为止
4,_objc_autoreleasePoolPrint
函数
- 实例一
// 系统提供的方法,用来打印AutoreleasePoolPage对象中存储的数据
extern void _objc_autoreleasePoolPrint(void);
int main(int argc, char * argv[]) {
@autoreleasepool {
YJPerson *person1 = [[[YJPerson alloc] init] autorelease];
YJPerson *person2 = [[[YJPerson alloc] init] autorelease];
@autoreleasepool {
YJPerson *person3 = [[[YJPerson alloc] init] autorelease];
YJPerson *person4 = [[[YJPerson alloc] init] autorelease];
@autoreleasepool {
YJPerson *person5 = [[[YJPerson alloc] init] autorelease];
YJPerson *person6 = [[[YJPerson alloc] init] autorelease];
_objc_autoreleasePoolPrint();
}
}
}
return 0;
}
// 打印
objc[91277]: ##############
objc[91277]: AUTORELEASE POOLS for thread 0x1192485c0
objc[91277]: 9 releases pending. // 总共9条数据
objc[91277]: [0x7fee0d806000] ................ PAGE (hot) (cold)
objc[91277]: [0x7fee0d806038] ################ POOL 0x7fee0d806038 // b1
objc[91277]: [0x7fee0d806040] 0x6000008b4fc0 YJPerson // person1
objc[91277]: [0x7fee0d806048] 0x6000008b5060 YJPerson // person2
objc[91277]: [0x7fee0d806050] ################ POOL 0x7fee0d806050 // b2
objc[91277]: [0x7fee0d806058] 0x6000008b5020 YJPerson // person3
objc[91277]: [0x7fee0d806060] 0x6000008b4f80 YJPerson // person4
objc[91277]: [0x7fee0d806068] ################ POOL 0x7fee0d806068 // b3
objc[91277]: [0x7fee0d806070] 0x6000008b4ec0 YJPerson // person5
objc[91277]: [0x7fee0d806078] 0x6000008b4ea0 YJPerson // person6
objc[91277]: ##############
- 实例二
int main(int argc, char * argv[]) {
@autoreleasepool {
for (int i = 0; i < 1000; i++) {
YJPerson *person = [[[YJPerson alloc] init] autorelease];
}
_objc_autoreleasePoolPrint();
}
return 0;
}
// 打印
objc[91615]: ##############
objc[91615]: AUTORELEASE POOLS for thread 0x10fbbc5c0
objc[91615]: 1001 releases pending.
// 第一个AutoreleasePoolPage对象,full表示已满
objc[91615]: [0x7f93f3802000] ................ PAGE (full) (cold)
objc[91615]: [0x7f93f3802038] ################ POOL 0x7f93f3802038
objc[91615]: [0x7f93f3802040] 0x600002f0b1c0 YJPerson
...
// 第二个AutoreleasePoolPage对象,hot表示正在使用
objc[91615]: [0x7f93f380d000] ................ PAGE (hot)
objc[91615]: [0x7f93f380d038] 0x600002f0d880 YJPerson
...
objc[91615]: ##############
5,源码分析
-
push
函数
static inline void *push()
{
id *dest;
if (DebugPoolAllocation) { // AutoreleasePoolPage对象未创建
// 创建对象并存储POOL_BOUNDARY
dest = autoreleaseNewPage(POOL_BOUNDARY);
} else { // 已创建
// 存储POOL_BOUNDARY
dest = autoreleaseFast(POOL_BOUNDARY);
}
assert(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);
return dest;
}
static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) { // 如果page未满
// 将POOL_BOUNDARY存储到page中
return page->add(obj);
} else if (page) { // 如果page已满
// 查找未满的page并存储POOL_BOUNDARY
return autoreleaseFullPage(obj, page);
} else {
return autoreleaseNoPage(obj);
}
}
id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page)
{
assert(page == hotPage());
assert(page->full() || DebugPoolAllocation);
// 查找未满的page
do {
if (page->child) page = page->child;
// 如果没有就创建
else page = new AutoreleasePoolPage(page);
} while (page->full());
setHotPage(page);
// 将POOL_BOUNDARY存储到page中
return page->add(obj);
}
-
autorelease
函数
static inline id autorelease(id obj)
{
assert(obj);
assert(!obj->isTaggedPointer());
// 存储autorelease对象
id *dest __unused = autoreleaseFast(obj);
assert(!dest || dest == EMPTY_POOL_PLACEHOLDER || *dest == obj);
return obj;
}
-
pop
函数
// 简化代码
static inline void pop(void *token)
{
AutoreleasePoolPage *page;
id *stop;
page = pageForPointer(token);
stop = (id *)token;
if (PrintPoolHiwat) printHiwat();
// 释放autorelease对象
page->releaseUntil(stop);
}
void releaseUntil(id *stop)
{
// 释放当前page中的autorelease对象
while (this->next != stop) {
AutoreleasePoolPage *page = hotPage();
// 如果当前page都释放完了还没遇到POOL_BOUNDARY,就继续释放上一个page的
while (page->empty()) {
page = page->parent;
setHotPage(page);
}
page->unprotect();
// 依次取出autorelease对象
id obj = *--page->next;
memset((void*)page->next, SCRIBBLE, sizeof(*page->next));
page->protect();
// 释放autorelease对象
if (obj != POOL_BOUNDARY) {
objc_release(obj);
}
}
setHotPage(this);
}
四,autoreleasepool和runloop的关系
1,autorelease
对象何时释放
- 并非在方法结束时释放
- (void)viewDidLoad {
[super viewDidLoad];
YJPerson *person = [[[YJPerson alloc] init] autorelease];
NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(@"%s", __func__);
}
// 打印
-[ViewController viewDidLoad]
-[ViewController viewWillAppear:]
-[YJPerson dealloc] // 没在viewDidLoad后面调用
-[ViewController viewDidAppear:]
- 并非在
main
函数中@autoreleasepool
结束时释放
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
NSLog(@"%s", __func__);
}
}
- (void)viewDidLoad {
[super viewDidLoad];
YJPerson *person = [[[YJPerson alloc] init] autorelease];
}
// 打印
-[YJPerson dealloc] // @autoreleasepool还没结束
2,系统在主线程的runloop
中注册了2个observer
- 查看
observer
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", [NSRunLoop mainRunLoop]);
}
// 部分打印
observers = (
"<CFRunLoopObserver 0x600001330320 [0x7fff80617cb0]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4808bf54),
context = <CFArray 0x600002c607e0 [0x7fff80617cb0]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7f9c54802048>\n)}}",
"<CFRunLoopObserver 0x6000013303c0 [0x7fff80617cb0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4808bf54),
context = <CFArray 0x600002c607e0 [0x7fff80617cb0]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7f9c54802048>\n)}}"
)
CFRunLoopActivity
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 1,进入runloop
kCFRunLoopBeforeTimers = (1UL << 1), // 2,即将处理timers
kCFRunLoopBeforeSources = (1UL << 2), // 4,即将处理sources
kCFRunLoopBeforeWaiting = (1UL << 5), // 32,即将休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 64,刚被唤醒
kCFRunLoopExit = (1UL << 7), // 128,退出runloop
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
- 第一个
observer
1>
activities
为0x1
(十进制为1),所以它是用来监听kCFRunLoopEntry
的2>当监听到
kCFRunLoopEntry
时,会调用objc_autoreleasePoolPush
函数
- 第二个
observer
1>
activities
为0xa0
(十进制为160 = 32 + 128),所以它是用来监听kCFRunLoopBeforeWaiting
和kCFRunLoopExit
的2>当监听到
kCFRunLoopBeforeWaiting
时,会先调用objc_autoreleasePoolPop
函数,再调用objc_autoreleasePoolPush
函数3>当监听到
kCFRunLoopExit
时,会调用objc_autoreleasePoolPop
函数
- 图解
- 说明
1>在程序运行过程中,主线程的
runloop
不会退出,它会一直循环的处理事件2>如果没有事件
runloop
就会休眠,在休眠之前会调用objc_autoreleasePoolPop
函数,该函数会释放所有的autorelease
对象3>所以
autorelease
对象是在当前循环休眠之前释放的
3,局部对象何时释放
- (void)viewDidLoad {
[super viewDidLoad];
YJPerson *person = [[YJPerson alloc] init];
NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(@"%s", __func__);
}
// 打印
-[ViewController viewDidLoad]
-[YJPerson dealloc] // 在方法结束时释放,因为ARC生成的是release,而不是autorelease
-[ViewController viewWillAppear:]
-[ViewController viewDidAppear:]