iOS中Block介绍(二)内存管理与其他特性
我们在前一章介绍了block的用法,而正确使用block必须要求正确理解block的内存管理问题。这一章,我们只陈述结果而不追寻原因,我们将在下一章深入其原因。
一、block放在哪里
我们针对不同情况来讨论block的存放位置:
1.栈和堆
以下情况中的block位于堆中:
- void foo()
- {
- __block int i = 1024;
- int j = 1;
- void (^blk)(void);
- void (^blkInHeap)(void);
- blk = ^{ printf("%d, %d\n", i, j);};//blk在栈里
- blkInHeap = Block_copy(blk);//blkInHeap在堆里
- }
- - (void)fooBar
- {
- _oi = 1;
- OBJ1* oj = self;
- void (^oblk)(void) = ^{ printf("%d\n", oj.oi);};
- void (^oblkInHeap)(void) = [oblk copy];//oblkInHeap在堆中
- }
2.全局区
以下情况中的block位于全局区:
- static int(^maxIntBlock)(int, int) = ^(int a, int b){return a>b?a:b;};
- - (void)fooBar
- {
- int(^maxIntBlockCopied)(int, int) =[maxIntBlock copy];
- }
- void foo()
- {
- int(^maxIntBlockCopied)(int, int) = Block_copy(maxIntBlock);
- }
需要注意的是,这里复制过后的block依旧位于全局区,实际上,复制操作是直接返回了原block对象。
二、block引用的变量在哪里
1.全局区
全局区的变量存储位置与block无关:
- static int gVar = 0;
- //__block static int gMVar = 1;
- void foo()
- {
- static int stackVar = 0;
- // __block static int stackMVar = 0;
- }
注意:static变量是不允许添加__block标记的
2.堆栈

此时,你可能会问,当函数foo返回后,栈上的j已经回收,那么blkInHeap怎么能继续使用它?这是因为没有__block标记的变量,会被当做实参传入block的底层实现函数中,当block中的代码被执行时,j已经不是原来的j了,所谓物是人非就是这样吧~
另外,如果使用到变量j的所有block都没有被复制至heap,那么这个变量j也不会被复制至heap。
因此,即使将j++这一句放到blk()这句之前,这段代码执行后,控制台打印结果也是:1024, 1。而不是1024, 2
三、其他特性
1.复制的行为
对block调用复制,有以下几种情况:
1.对全局区的block调用copy,会返回原指针,并且这期间不处理任何东西(至少目前的内部实现是这样);
2.对栈上的block调用copy,每次会返回新复制到堆上的block的指针,同时,所有__block变量都会被复制至堆一份(多次拷贝,只会生成一份)。
3.对已经位于heap上的block,再次调用copy,只会增加block的引用计数。
为什么我们不讨论retian的行为?原因是并没有Block_retain()这样的函数,而且objc里面的retain消息发送给block对象后,其内部实现是什么都不做。
2.objc类中的block复制
objc类实例方法中的block如果被复制至heap,那么当前实例会被增加引用计数,当这个block被释放时,此实例会被减少引用计数。
但如果这个block没有使用当前实例的任何成员,那么当前实例不会被增加引用计数。这也是很自然的道理,我既然没有用到这个instance的任何东西,那么我干嘛要retian它?
我们要注意的一点是,我看到网上有很多人说block引起了实例与block之间的循环引用(retain-cycle),并且给出解决方案:不直接使用self而先将self赋值给一个临时变量,然后再使用这个临时变量。
但是,大家注意,我们一定要为这个临时变量增加__block标记(多谢第三篇文章回帖网友的提醒)。
这一章我们以结果导向的方式来说明了各种情况下,block的内存问题,下一章,我将剖析运行时库的源码,从根源阐述block的行为。也就是过程导向的方式了。
iOS中Block介绍(二)内存管理与其他特性的更多相关文章
- iOS之Block总结以及内存管理
block定义 struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(v ...
- iOS中Block介绍(一)基础
ios开发block的使用指南,以及深入理解block的内存管理,也适用于osx开发.讨论范围:block的使用,内存管理,内部实现.不包含的内容:gc arc下的block内存,block在c++中 ...
- iOS中Block介绍 基础
ios开发block的使用指南,以及深入理解block的内存管理,也适用于osx开发.讨论范围:block的使用,内存管理,内部实现.不包含的内容:gc arc下的block内存,block在c++中 ...
- 看朋友日志发现的一个ios下block相关的内存管理问题,非常奇怪,请大家帮忙一起来回答!
http://blog.csdn.net/fengsh998/article/details/38090205 这篇文章以下是我的回复.相同的代码仅仅是把变量的定义从局部变量改为类的成员变量就发现了非 ...
- iOS开发系列—Objective-C之内存管理
概述 我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在ObjC中对象时存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是由系统自己管理的,放在栈上).如果一个对象创建并使用后没 ...
- iOS经典面试题总结--内存管理
iOS经典面试题总结--内存管理 内存管理 1.什么是ARC? ARC是automatic reference counting自动引用计数,在程序编译时自动加入retain/release.在对象被 ...
- iOS 中Block以及Blocks的使用,闭包方法调用
OC: -(void)dataWithUrl:(NSString*)string AndId:(NSInteger)id returnName:(void(^)(NSString*name))back ...
- iOS学习笔记之ARC内存管理
iOS学习笔记之ARC内存管理 写在前面 ARC(Automatic Reference Counting),自动引用计数,是iOS中采用的一种内存管理方式. 指针变量与对象所有权 指针变量暗含了对其 ...
- 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...
随机推荐
- Cocos2d-x 安装教程for mac(Xcode)
cocos2d v3.x 版本出来后,从配置安装到创建项目都是命令行,下面简单说一下. 1. 下载地址 http://cn.cocos2d-x.org/download/ (虽然没有标明 for ...
- XML实例入门2
工具:notepad++.VS2008(MSXML6.0) 来自msdn的例子(经过修改,因为升级到MSXML6.0,有些关键字不太一样了), 需要文件books.xml,books.vsd(博客只支 ...
- hdu5461 Largest Point(沈阳网赛)
Largest Point Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total ...
- Let the Balloon Rise(map)
Let the Balloon Rise Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Oth ...
- SPOJ 3267 求区间不同数的个数
题意:给定一个数列,每次查询一个区间不同数的个数. 做法:离线+BIT维护.将查询按右端点排序.从左到右扫,如果该数之前出现过,则将之前出现过的位置相应删除:当前位置则添加1.这样做就保证每次扫描到的 ...
- [置顶] PHP如何扩展和如何在linux底层对php扩展?
虽然大部分php工程师都不需要知道php的C代码核心是如何运作的,有些人可能知道有个dl()函数.或者使用过一些第三方的类库,这些正是本文的重点之一. 希望对那些想把php带向更 ...
- [转] C#.Net Socket网络通讯编程总结
1.理解socket1).Socket接口是TCP/IP网络的应用程序接口(API).Socket接口定义了许多函数和例程,程序员可以用它们来开发TCP/IP网络应用程序.Socket可以看成是网络通 ...
- SQL中日期格式转换为年月日
)
- ubuntu10.04 安装NVIDIA GT 420M驱动
安装ubuntu已经好几天了,由于显卡驱动没装,屏幕在600X800下的效果很难看,于是就想办法,查阅资料终于安装成功了,下面将我的安装方法记录下来以供大家参考. 借鉴:ubuntu12.04下安装N ...
- Hadoop学习之Hadoop集群搭建
1.检查网络状况 Dos命令:ping ip地址,同时,在Linux下通过命令:ifconfig可以查看ip信息2.修改虚拟机的ip地址 打开linux网络连接,在桌面右上角,然后编辑ip地址, ...