美文网首页
block详解<3>: block在内存区域中是如何分布的

block详解<3>: block在内存区域中是如何分布的

作者: 菜小狼 | 来源:发表于2016-09-23 16:12 被阅读0次

    如果大家还有映像的话,我们在前面讲解结构体 _block_impl的时候,里面有一个成员叫isa,这个代表了block在内存区域中的分布。如果你看了一些关于block的文章,isa会有三种取值:

    isa = &_NSConcreteStackBlock;
    isa = &_NSConcreteMallocBlock;
    isa = &_NSConcreteGlobalBlock;

    但是clang出来的文件,里面都是第一种,说明这并不是block在内存中的真正分布。真正的分布,我们可以通过打印来确定。


    屏幕快照 2016-09-22 2.35.54 PM.png 屏幕快照 2016-09-22 2.49.47 PM.png

    第二张图的打印结果是NSMallocBlock,同时我又试了其他的几种情况,发现都是NSMallocBlock,说明在ARC环境下,栈上的block默认都会被拷贝到堆上,也就是说,在ARC环境下,block只有两种类型:NSGlobalBlock 和 NSMallocBlock。那么到底有没有特殊的情况呢?后来查查资料,发现还真有。

    屏幕快照 2016-09-22 5.09.57 PM.png

    执行上面的代码的时候,直接crash了,从错误的提示可以看出,是某个东西的内存过早的释放了。我们仔细观察一下控制台,发现数组的第一个元素是NSMallocBlock类型,这是被分配在堆上的block;数组的第二个元素有点儿问题:发现它的内存地址跟argv的格式比较像,而argv是函数的参数,内存是被分配在栈内存上的,所以第二个block也是被分配在栈内存上的,并没有被拷贝到堆内存上。然后我们换一种写法:

    屏幕快照 2016-09-22 5.21.23 PM.png

    发现可以正常运行,并且打印的结果也是我们想要的。

    我们再看一下上面的数组的初始化函数

    + (instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
    

    这个函数是一个可变函数,只有第一个参数被显示的申明为ObjectType类型,也就是id类型,其他的参数并没有被显示的申明为id类型。这也验证了第一种情况下第一个block被分配在堆上,第二个block被分配在栈上。而我们的第二种写法是,先申明一下block,在block到底是什么一文中,我们已经说了,block其实就是一个函数指针,也可以说它是一个id类型,所以在第二种写法下,两个block都被显示的申明为id类型,所以都被分配在堆上,所以第二种情况没有问题。

    由此我们可以得出一个结论:block作为函数的参数时,一定要被显示的申明为id类型,才会被分配在堆上。
    参考文章

    ARC 下向 NSArray 添加 Block 元素的一个小坑

    相关文章

      网友评论

          本文标题:block详解<3>: block在内存区域中是如何分布的

          本文链接:https://www.haomeiwen.com/subject/qxityttx.html