一、block放在哪里

我们针对不同情况来讨论block的存放位置:

1.栈和堆

以下情况中的block位于堆中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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位于全局区:

1
2
3
4
5
6
7
8
9
10
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无关:

1
2
3
4
5
6
7
8
static int gVar = 0;
//__block static int gMVar = 1;
 
void foo()
{
    static int stackVar = 0;
//    __block static int stackMVar = 0;
}

注意,static变量是不允许添加__block标记的

2.堆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void foo()
{
    __block int i = 1024;//此时i在栈上
    int j = 1;//此时j在栈上
    void (^blk)(void);
    blk = ^{printf("%d, %d\n", i, j); };//此时,blk已经初始化,它会拷贝没有__block标记的常规变量自己所持有的一块内存区,这块内存区现在位于栈上,而对于具有__block标记的变量,其地址会被拷贝置前述的内存区中
    blk();//1024, 1
    void(^blkInHeap)(void) = Block_copy(blk);//复制block后,block所持有的内存区会被拷贝至堆上,此时,我们可以说,这个block现在位于堆上
    blkInHeap();//1024,1
    i++;
    j++;
    blk();//1025,1
    blkInHeap();//1025,1
}

让我们一步步剖析:

首先,我们在栈上创建了变量ij,并赋予初始值,然后创建一个block变量名为blk,但未赋值。

然后我们初始化这个blk,赋值为一个只有一句printf的block,值得注意的是,一个block一旦创建,其引用到的常规变量会进行如下操作:

没有__block标记的变量,其值会被复制一份到block私有内存区

有__block标记的变量,其地址会被记录在block私有内存区

然后调用blk,打印1024, 1很好理解

接下来复制blk到堆,名曰blkInHeap,调用之,打印1024, 1也很好理解

接下来我们为ij增值,使其变为1025和2,此时再调用blk或者blkInHeap,会发现结果为1025, 1,这是因为变量j早已在创建原始的block时,被赋值进block的私有内存区,后续对i的操作并非操作的私有内存区的复制品,当调用blk或者blkInHeap时,其打印使用的是私有内存区的复制品,故而打印结果依旧为1;而变量j的修改会实时生效,因为block记录的是它的地址,通过地址来访问其值,使得外部对j的修改在block中得以生效。对于变量i来讲,可算是物是人非吧?

因此,无论j++这一句放到blk()这句之前或者之后,只要它位于block初始化之后,这段代码执行的控制台打印结果都会是:1024, 1。而不是1024, 2(假设不调用i++)

Block(二)内存管理与其他特性-b的更多相关文章

  1. Block介绍(二)内存管理与其他特性

    我们在前一章介绍了block的用法,而正确使用block必须要求正确理解block的内存管理问题.这一章,我们只陈述结果而不追寻原因,我们将在下一章深入其原因. 一.block放在哪里 我们针对不同情 ...

  2. iOS中Block介绍(二)内存管理与其他特性

    我们在前一章介绍了block的用法,而正确使用block必须要求正确理解block的内存管理问题.这一章,我们只陈述结果而不追寻原因,我们将在下一章深入其原因. 一.block放在哪里 我们针对不同情 ...

  3. block之---内存管理

    首先简单说下MRC和ARC MRC: 手动管理内存,需要自己去释放内存, 如果对象的引用计数器为0时对象就会被释放. 属性修饰策略:assign, retain, copy ARC: ARC是编译器特 ...

  4. Android笔记--Bitmap(二)内存管理

    Bitmap(二) 内存管理 1.使用内存缓存保证流畅性 这种使用方式在ListView等这种滚动条的展示方式中使用最为广泛, 使用内存缓存 内存缓存位图可以提供最快的展示.但代价就是占用一定的内存空 ...

  5. Block(二)内存管理与其他特性

    一.block放在哪里 我们针对不同情况来讨论block的存放位置: 1.栈和堆 以下情况中的block位于堆中: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  6. Spark(二): 内存管理

    Spark 作为一个以擅长内存计算为优势的计算引擎,内存管理方案是其非常重要的模块: Spark的内存可以大体归为两类:execution和storage,前者包括shuffles.joins.sor ...

  7. cocos2d-x游戏引擎核心之二——内存管理

    (一) cocos2d-x 内存管理 cocos2d里面管理内存采用了引用计数的方式,具体来说就是CCObject里面有个成员变量m_uReference(计数); 1, m_uReference的变 ...

  8. block没那么难(二):block和变量的内存管理

    本系列博文总结自<Pro Multithreading and Memory Management for iOS and OS X with ARC> 了解了 block的实现,我们接着 ...

  9. iOS Block 内存管理的探讨

    在很多情况下Block是造成程序循环引用内存泄漏的元凶.下面我们就讲解一下block对内存管理的影响.在讲解之前.希望大家对block有一定的了解.如果大家还不是太清楚block的实现原理.希望大家可 ...

随机推荐

  1. GIF添加3D加速

    由于浏览器内核对Gif格式的图片会产生卡的情况,所以我们需要告诉浏览器,开启一下加速,方法很简单,就是利用css3的特性,强制告诉浏览器,这是个元素,需要3D转换,请务必开启加速效果 方法1 给gif ...

  2. Robotframework(4):创建变量的类型和使用

    转载:http://www.cnblogs.com/CCGGAAG/p/7800321.html 实际的测试过程中,编写脚本时,我们需要创建一些变量来暂时或者永久性的存储数据,那么在Robotfram ...

  3. android自己定义进度值可拖动的seekbar

    近期忙找实习,加上实验室在推新项目,须要学习新知识.所以非常长一段时间没去整理了官博客了,github也蛮久没更新.非常羞愧.接下来还是要坚持写. 今天就简单的写一下我在项目中用到的算自己定义seek ...

  4. JAVA 报错exe4j中this executable was created with an evaluation 怎么办

    如果使用未破解注册的exe4j打包JAR文件为EXE,运行EXE的时候就会出现下面的提示   打开exe4j软件,Change License或者是输入序列号,然后用注册机算一个注册码即可  

  5. ionic3中创建pipe管道

    1.使用ionic cli创建pipe管道文件 ionic g pipe parse-date 该命令会在src文件夹创建pipes/parse-date/parse-date.ts文件,并且会在pi ...

  6. Bootstrap相关网站中简单的等待提醒

    一.在页面中加入如下代码 <div class="modal fade" tabindex="-1" role="dialog" id ...

  7. [转] libtool的作用及应用

    今天使用 autoconf 的时候遇到一个 libtool 的问题,觉得这个东西挺有意思,找了个文档过来,暂时记录. 转自:http://blog.csdn.net/larntin2002/artic ...

  8. 【 D3.js 入门系列 — 11 】 入门总结

    D3 新专题首页 一转眼,这个入门系列已经积累了二十二篇文章之多,我想作为 D3.js 这款数据可视化工具的入门来说已经足够了.相信仅仅要看完本系列.以后全然能够在辅以查询的情况下完毕大部分可视化工作 ...

  9. Tomcat上文件的绝对路径访问笔记

    部署到Tomcat上的web项目的文件在代码中访问,可以先通过request获取到项目的根目录绝对路径,然后自己拼接子目录路径,直到文件.方法如下: String realpath=request.g ...

  10. 如何在MyEclipse配置Gradle

    1.首先下载gradle gdk http://services.gradle.org/distributions 选一个bin或者all的下载即可 2.配置path GRADLE_HOME  D:\ ...