block存储区域——怎样验证block在栈上,还是堆上

时间:2022-09-18 21:48:52

Block存储区域

首先,须要引入三个名词:
● _NSConcretStackBlock
● _NSConcretGlobalBlock
● _NSConcretMallocBlock
正如它们名字显示得一样,表明了block的三种存储方式:栈、全局、堆。block对象中的isa的值就是上面当中一个,以下開始说明哪种block存储在栈、堆、全局。block为何是个对象,參考点击打开链接

------------【要点1】:全局block------------

● 定义在函数外面的block是global类型的
● 定义在函数内部的block,可是没有捕获不论什么自己主动变量,那么它也是全局的。比方以下这种代码
typedef int (^blk_t)(int);
for(...){
blk_t blk = ^(int count) {return count;};
}
尽管,这个block在循环内,可是blk的地址总是不变的。说明这个block在全局段。注:针对没有捕获自己主动变量的block来说,尽管用clang的rewrite-objc转化后的代码中仍显示_NSConcretStackBlock,可是实际上不是这种。下图能够证明该类型的block是全局的。Xcode5.1.1调试结果
block存储区域——怎样验证block在栈上,还是堆上
不管ARC与否,上图控制台输出是 <__NSGlobalBlock__: 0x10000f280>,这可能是编译器的优化,本人猜測,没有求证。所以用clang的-rewrite-objc是不准确的。

------------【要点2】:栈block--------------

这样的情况,在非ARC下是无法编译的,在ARC下能够编译
typedef void (^block_t)() ;
-(block_t)returnBlock{
__block int add=10;
return ^{printf("add=%d\n",++add);};
}
这是由于:block捕获了栈上的add自己主动变量,此时add已经变成了一个结构体,而block中拥有这个结构体的指针。即假设返回block的话就是返回局部变量的指针。而这一点恰是编译器已经断定了。在ARC下能够编译过,是由于ARC使用了autorelease了。
再说一个场景:
-(block_t)returnBlock{
__block int add=10;
block_t blk_h =^{printf("add=%d\n",++add);};
return blk_h;
}
block_t bb = [self returnBlock];
bb();

这段代码,仅仅是使用了一个自己主动block变量,能够编过,可是造成程序崩溃了。

假设在返回block的时候加上copy,能够输出正确的数值11

------------【要点3】:堆上的block ----------------

有时候我们须要调用block 的copy函数,将block复制到堆上。看以下的代码:
-(id) getBlockArray{
int val =10;
return [NSArray arrayWithObjects:
^{NSLog(@"blk0:%d",val);},
^{NSLog(@"blk1:%d",val);},nil];
} id obj = getBlockArray();
typedef void (^blk_t)(void);
blk_t blk = (blk_t){obj objectAtIndex:0};
blk();
这段代码在最后一行blk()会异常,由于数组中的block是栈上的。由于val是栈上的。解决的方法就是调用copy方法。这样的场景,ARC也不会为你加入copy,由于ARC不确定,採取了保守的措施:不加入copy。所以ARC下也是会异常退出。

---------------------【要点4】copy的使用-----------------------------------

无论block配置在何处,用copy方法复制都不会引起不论什么问题。
在ARC环境下,假设不确定是否要copy block虽然copy就可以。ARC会打扫战场。
【注意】:
● 在栈上调用copy那么拷贝到堆上
● 在全局block调用copy什么也不做
● 在堆上调用block 引用计数添加

------------------【对《Objective-C 高级编程》的挑战】-----------------------

    笔者用Xcode 5.1.1 iOS sdk 7.1 编译发现:并不是《Objective-C 高级编程》这本书中描写叙述的那样,-rewrite-objc这个命令转化的中间代码,并不可靠。
    block在ARC和非ARC有巨大区别:以下笔者用两种方式来验证:
1.通过Xcode调试结果,附图

2.通过变量的地址 int val肯定是在栈上的,我保存了val的地址,看看block调用前后是否变化。输出一致说明是栈上,不一致说明是堆上。
【第一个方法】,最直观.代码例如以下,非常easy。block捕获了变量val(不管val是否是__block)
-(void) stackOrHeap{
__block int val =10;
blkt1 s= ^{
return ++val;};
s();
blkt1 h = [s copy];
h();
}

在非ARC和ARC下,调试结果例如以下:

block存储区域——怎样验证block在栈上,还是堆上block存储区域——怎样验证block在栈上,还是堆上
能够看到非ARC下一个是stack一个是Malloc。ARC下都是Malloc


【第二个方法】,声明一个局部变量指针。通过指针来看
typedef int (^blkt1)(void) ;
-(void) stackOrHeap{
__block int val =10;
int *valPtr = &val;//使用int的指针,来检測block究竟在栈上,还是堆上
blkt1 s= ^{
NSLog(@"val_block = %d",++val);
return val;};
s();
NSLog(@"valPointer = %d",*valPtr);
}
在ARC下>>>>>>>>>>>该block被会直接生成到堆上了。看log: val_block = 11 valPointer = 10
在非ARC下>>>>>>>>>该block还是在栈上的。 看log:val_block = 11 valPointer = 11

调用copy之后的结果呢:

-(void) stackOrHeap{
__block int val =10;
int *valPtr = &val;//使用int的指针,来检測block究竟在栈上,还是堆上
blkt1 s= ^{
NSLog(@"val_block = %d",++val);
return val;};
blkt1 h = [s copy];
h();
NSLog(@"valPointer = %d",*valPtr);
}

在ARC下>>>>>>>>>>>无效果。 val_block = 11 valPointer = 10

在非ARC下>>>>>>>>>确实拷贝到堆上了。 val_block = 11 valPointer = 10

----------------【总结】-----------------

用这个表格来表示。捕获变量包含只读取变量,和__block这样的写变量,两种方式(事实上结果是一样的)
block存储区域——怎样验证block在栈上,还是堆上
在ARC下:似乎已经没有栈上的block了,要么是全局的,要么是堆上的
在非ARC下:存在这栈、全局、堆这三种形式。

block存储区域——怎样验证block在栈上,还是堆上的更多相关文章

  1. Block存储区域

    Block存储区域 首先,需要引入三个名词: ● _NSConcretStackBlock ● _NSConcretGlobalBlock ● _NSConcretMallocBlock 正如它们名字 ...

  2. OC高级编程——深入block,如何捕获变量,如何存储在堆上

    OC高级编程——深入block,如何捕获变量,如何存储在堆上   首先先看几道block相关的题目 这是一篇比较长的  博文 ,前部分是block的测试题目,中间是block的语法.特性,block讲 ...

  3. JS栈内存与堆内存

    ㈠JavaScript变量 ⒈分类 ⑴JavaScript中的变量分为基本类型和引用类型. ⑵基本类型就是保存在栈内存中的简单数据段. ⑶引用类型指的是那些保存在堆内存中的对象. ⒉基本类型  基本类 ...

  4. JavaScript 数据结构与算法之美 - 栈内存与堆内存 、浅拷贝与深拷贝

    前言 想写好前端,先练好内功. 栈内存与堆内存 .浅拷贝与深拷贝,可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScri ...

  5. go语言的局部变量在堆上还是栈上?

    在讨论之前,先看如下代码: type treeNode struct { value int left, right *treeNode } func createNode(value int) *t ...

  6. OC 中的block存储位置

    以下所有在ARC情况下: 一.block块的存储位置(block块入口地址):可能存放在2个地方:代码区.堆区(程序分5个区,还有常量区.全局区和栈区,对于MRC情况下代码还可能存在栈区.关于分区详细 ...

  7. Lucene4&period;2源码解析之fdt和fdx文件的读写——fdx文件存储一个个的Block,每个Block管理着一批Chunk,通过docID读取到document需要完成Segment、Block、Chunk、document四级查询,引入了LZ4算法对fdt的chunk docs进行了实时压缩&sol;解压

    前言 通常在搜索打分完毕后,IndexSearcher会返回一个docID序列,但是仅仅有docID我们是无法看到存储在索引中的document,这时候就需要通过docID来得到完整Document信 ...

  8. Lucene4&period;2源码解析之fdt和fdx文件的读写&lpar;续&rpar;——fdx文件存储一个个的Block,每个Block管理着一批Chunk,通过docID读取到document需要完成Segment、Block、Chunk、document四级查询,引入了LZ4算法对fdt的chunk docs进行了实时压缩&sol;解压

    2       索引读取阶段 当希望通过一个DocId得到Doc的全部内容,那么就需要对fdx/fdt文件进行读操作了.具体的代码在CompressingStoredFieldsReader类里面.与 ...

  9. 局部变量存储区域静态变量存储区域static变量存储区域

    局部变量存储区域静态变量存储区域static变量存储区域 常见的存储区域可分为: 1.栈 由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区.里面的变量通常是局部变量.函数参数等. 2.堆 ...

随机推荐

  1. hdu A Bug&&num;39&semi;s Life

    题目意思:给定一系列数对,例如a和b,表示a和b不是同一种性别,然后不断的给出这样的数对,问有没有性别不对的情况. 例如给定: 1    2 3    4 1    3 那这里就是说1和2不是同种性别 ...

  2. Codeforces 733F Drivers Dissatisfaction

    题意:有n个点,m条边,每条边有不满意度w[i],以及减小一个不满意度代价c[i],问给你s元用来减少代价,找到一个总不满意度最小的生成树,保证有解.(减少后的不满意度可以为负数)思路:显然所有的钱都 ...

  3. 未能加载文件或程序集&OpenCurlyDoubleQuote;SQLDAL”或它的某一个依赖项。系统找不到指定的文件

    1. 检查是否SQLDAL.DLL这个程序集文件是否存在,是否在Debug目录下(如果你是在Debug模式下调试).或者看看是否是配置文件中的名称和实际的dll的名称不对应. 2. 你使用的是Asse ...

  4. Apple移动设备处理器指令集 armv6、armv7、armv7s及arm64-b

    Arm处理器,因为其低功耗和小尺寸而闻名,几乎所有的手机处理器都基于arm,其在嵌入式系统中的应用非常广泛,它的性能在同等功耗产品中也很出色. Armv6.armv7.armv7s.arm64都是ar ...

  5. 学php之翻译wordpress&lpar;1&rpar;

    单看文件结构,wordpress分了3个文件夹 wp-admin,wp-content,wp-includes 和零散的一堆php,暂时不清楚各自的分工 入口文件是index.php <?php ...

  6. web项目 easyui-datagrid开发实践

    一,引言 工作的需要,做了3年的wpf(mvvm)……,又因为项目的需求,回归到web的开发. ■  3 years ago,vue是我三年前没用过的玩意儿. ■  3 years ago,boots ...

  7. iterm2 快捷键(转载)

    Mac 下 iterm2 的快捷键,转自:https://github.com/sumiaowen/iterm2-shortcuts iterm2-shortcuts(iterm 2 快捷键) 标签 ...

  8. 【Java千问】你了解代理模式吗?

    代理模式详解 1 什么是代理模式? 一句话描述:代理模式是一种使用代理对象来执行目标对象的方法并在代理对象中增强目标对象方法的一种设计模式. 详细描述: 1.理论基础-代理模式是设计原则中的“开闭原则 ...

  9. springboot 学习之路 6(集成durid连接池)

    目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...

  10. C&plus;&plus;程序设计方法3:禁止自动类型转换

    禁止自动类型转换 explicit #include <iostream> using namespace std; class Src;//前置类型声明,因为在Dst中要用到Src的类 ...