设为首页 加入收藏

TOP

block本质探寻七之内存管理(三)
2019-08-26 07:00:51 】 浏览:83
Tags:block 本质 探寻 内存 管理
p;dst->blockPer, (void*)src->blockPer, 8/*BLOCK_FIELD_IS_BYREF*/);} static void __test2_block_dispose_0(struct __test2_block_impl_0*src) {_Block_object_dispose((void*)src->blockPer, 8/*BLOCK_FIELD_IS_BYREF*/);} static struct __test2_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __test2_block_impl_0*, struct __test2_block_impl_0*); void (*dispose)(struct __test2_block_impl_0*); }

分析:

<1>我们发现,__block修饰的blockPerl实例对象,系统也会自动生成一个新的对象__Block_byref_blockPer_1;被引用的类对象以指针的形式存在于该结构体中(Person *blockPer),该指针指向[[Person alloc] init]这个实例对象(位于堆区);

<2>在__Block_byref_blockPer_1结构体中,还存在__Block_byref_id_object_copy和__Block_byref_id_object_dispose两个函数指针,分别指向__Block_byref_id_object_copy_131函数和__Block_byref_id_object_dispose_131函数(作用同上),如下:

static void __Block_byref_id_object_copy_131(void *dst, void *src) {
 _Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
 _Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}

很显然,这两个函数的作用也是针对某个对象的内存管理,那是哪个对象呢?

首先,_Block_object_assign和_Block_object_dispose的第三个参数为131,是指__block修饰实例对象的情形;

其次,dst是__Block_byref_blockPer_1对象的地址,加40是什么?我们算出Person *blockPer指针的地址偏移量正好为40(8+8+4+4+8+8,指针变量占8个字节),那么可以肯定,上述两个函数就是对Person *blockPer指向的实例对象[[Person alloc] init]的内存管理;

所以,我们可以推测出以下结构:block对象__test2_block_impl_0通过其内部成员变量blockPer持有__Block_byref_blockPer_1对象,而__Block_byref_blockPer_1对象又通过其内部成员变量blockPer持有[[Person alloc] init]实例对象;

我们知道,前者通过_test2_block_copy_0函数和__test2_block_dispose_0函数进行内存管理,其持有必定是强引用,,这点没问题;而后者的持有是通过__Block_byref_id_object_copy_131函数和__Block_byref_id_object_dispose_131函数进行内存管理,但其持有是强引用还是弱引用呢?往下看;

//__weak修饰

__block __weak Person *blockPer = per;

//clang:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-9.0.0 main.m(注:要设置runtime,否则编译会报错)

struct __Block_byref_blockPer_1 {
  void *__isa;
__Block_byref_blockPer_1 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 Person *__weak blockPer;
};

//打印

2019-01-17 12:17:20.776779+0800 MJ_TEST[1598:105742] 30
2019-01-17 12:17:20.777113+0800 MJ_TEST[1598:105742] -[Person dealloc]
Program ended with exit code: 0

分析:

<1>我们发现,如果没有__weak修饰,blockPer格式为Person *blockPer,默认为strong类型;__weak修饰后,则会变成weak类型;

<2>根据之前的分析,其实__Block_byref_blockPer_1对象对[[Person alloc] init]实例对象的引用,取决于指向该实例对象的指针类型(因为对象引用是指针传递,前面已讲过);

------!!!但是,该规则仅限于ARC模式的情形,MRC模式下,如果指针是strong类型,系统并不会执行retain操作!!!

这里有个问题,为什么__weak修饰后,Person实例对象打印前没有被销毁呢?因为该实例对象的作用域在test2()函数体内,而block的回调也在函数体内,因此回调时,该实例对象并没有被销毁;

接下来,我们可以验证下: 

分析:此时,block回调前,Person实例对象就被销毁了,说明block对象对实例对象的引用取决于Person对象指针的引用类型;

我们再切换到MRC模式下看看:

//代码

void test4()
{
    Person *per = [[Person alloc] init];
    
    MyBlock block = [^{
        NSLog(@"%p", per);
    } copy];
    
    [per release];
    
    block();
    
    [block release];
}

//打印

2019-01-17 13:52:05.667590+0800 MJ_TEST[2106:151409] 0x10061add0
2019-01-17 13:52:05.668200+0800 MJ_TEST[2106:151409] -[Person dealloc]
Program ended with exit code: 0

首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇笔记:沙盒文件的拷贝 下一篇Swift构造

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目