Block 的内存管理
来源:互联网 发布:加盟网留言数据买卖 编辑:程序博客网 时间:2024/04/27 17:30
原文
block 有什么意义,特点等等,这些东西,实在是太复杂了,这里只是简单的总结一下block的内存管理。而且也仅仅限于objective-C的部分
Block memory
block 的内存管理,应该是最头疼的地方,就用这个来自WWDC的例子来解释一下吧。
当程序运行到这里时,stack 空间中有 shared 变量和 captured 变量。
这里可以看出,__block 变量开始是处于stack上的。
当程序运行到这里时,stack 空间中有 shared 变量,captured 变量和block1。
这里可以看出,block 类型的变量开始时也是处在stack上的。
当程序运行到这里时,stack 空间中有 shared 变量,captured 变量和block1。
这里值得注意的就是当我们直接修改stack 上的captured变量时,block1中的captured变量仍然是原来的数值10。事实上,从const 我们就可以看出,block1中的captured变量是不能被修改的而且是从stack原有变量的一个const 拷贝。在block1中访问的captured变量是const拷贝的,也就是说block1中captured = 10,而不是原有的stack上的值 20。当然,在block1中,我们也不能修改captured变量。
Copy block
block在一开始是处在stack上的,这是为了考虑到效率的原因,但是,有时候是需要block的生命周期长于一开始的stack,这时,我们就通过copy block 来将block复制到heap。
当程序执行完 block2 = [block1 copy];时,__block 类型变量shared,被复制到了heap中,很显然,shared变量需要被block和block2共享(当然还有stack也要共享),而block2被移动到heap中,很可能生命周期会长于stack,所以,shared也被复制到了heap中。而block2中的captured 也被复制到了heap中。
当程序执行完 block3 = [block2 copy];时, 我们看到的是,block2 和block3 其实指向的是同一片内存空间。事实上,block的数据结构中,保存了引用计数,而对于copy到heap中的block 再copy时,行为同普通对象retain一样,会使引用计数+1。那么如果我们对[block retain]会如何呢? 实际上什么都没有发生,至少在现在的runtime版本下。因为retain中,不仅有引用计数+1在,而且retain的返回值,必须同返回调用对象的地址一样,而block的地址是可能变化的(stack or heap),所以,这里retain的行为几乎是被忽略掉的。
当heap中的block变量先于stack被销毁时,如调用 [block2 release]; [block3 release];,heap中的block2,block3 由于引用计数为0 而被销毁,而 __block 变量shared则还在heap中,因为stack还要使用,block1 也要使用。
当heap中的block变量晚于stack时,显然,stack 被清除,function中也啥都没了。
最后,当block2 和block3 都被release之后。则恢复到最初状态
以下为实验结果:
结论:block创建时,处于栈上,对于引用外部的变量处理如下,栈变量拷贝一份存于栈中,对象变量引用计数不变。
当block被拷贝后,其中的栈变量被拷贝到堆中,外部对象引用会被retain,新block也被拷贝到堆中。block之间对于外部的变量,采用共享副本的方式。copyblock一般用于异步回调,防止栈block被释放了,但还没到调用block的时刻。一个copy应该对应一个release,当copyblock被释放后,里面的对象的引用计数自动减1。对于copyblock应注意避免循环持有和引用。
对于要在block内更改外部变量时或者不想外部变量被retain时,需加上__block或__weak。
block details
当我们写出一个Block literal expression
^ { printf("hello worldn"); }事实上,编译器为我们生成了如下结构struct __block_literal_1 { void *isa; int flags; int reserved; void (*invoke)(struct __block_literal_1 *); struct __block_descriptor_1 *descriptor; };void __block_invoke_1(struct __block_literal_1 *_block) { printf("hello worldn"); }static struct __block_descriptor_1 { unsigned long int reserved; unsigned long int Block_size; } __block_descriptor_1 = { 0, sizeof(struct __block_literal_1)}; 当Block literal expression 使用时 __block_literal_1 则会被初始化为:struct __block_literal_1 _block_literal = { &_NSConcreteStackBlock, (1<<29), <uninitialized>, __block_invoke_1, &__block_descriptor_1 };
- Block 的内存管理
- Block的内存管理
- Block 的内存管理
- Block 的内存管理
- block的内存管理
- Block 的内存管理
- Block 的内存管理
- block里的内存管理
- iOS的block内存管理
- Block的深入研究之Block的内存管理
- block的使用与内存管理
- iOS关于block的内存管理
- Objective-C的block内存管理
- 聊聊Block的内存管理那些事
- Block的内存管理以及变量Capture
- block内存管理
- block内存管理
- 内存管理和 Block
- c# 获取方法所在的命名空间 类名 方法名
- ffmpeg中的sws_scale算法性能测试
- 学习vi和vim编辑器(7):ex编辑器概述(2)
- BackBone 学习笔记 04 库函数Functions类
- Linux下的C编程实战【1】
- Block 的内存管理
- Android Studio 主题 字体
- 用C#开发加密狗程序
- Sicily1034-forest(DFS)
- android高级编程学习笔记--ToDoList第二版
- HighCharts之2D圆环图 donut
- RTree算法及介绍
- 【HTML5学习】HTML5学习整理笔记(一)
- 机器学习经典算法详解及Python实现--决策树(Decision Tree)