Block的内存管理

Block简单原理

详细原理:http://blog.csdn.net/wildfireli/article/details/22063001#0-tsina-1-77995-397232819ff9a47a7b7e80a40613cfe1
原理简单地说,就是将一个函数本身当成参数进行传递。
具体来看,Block果然是和OC中的NSObject类似,也是用struct实现出来的东西。这个是LLVM项目compiler-rt分析的block头文Block_private.h头文件中关于Block的struct声明:

struct Block_descriptor {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};

struct Block_layout {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */
};

我们发现Block_layout中也有一个isa指针,像极了NSobject内部实现struct中的isa指针。这里的isa可能指向三种类型之一的Block:

  • _NSConcreteGlobalBlock:全局类型Block,在编译器就已经确定,直接放在代码段__TEXT上。直接在NSLog中打印的类型为__NSGlobalBlock__
  • _NSConcreteStackBlock:位于栈上分配的Block,即__NSStackBlock__
  • _NSConcreteMallocBlock:位于堆上分配的Block,即__NSMallocBlock__

循环引用

在苹果使用ARC管理之前,Block的内存管理需要区分是Global(全局)、Stack(栈)还是Heap(堆)。而在使用了ARC之后,苹果自动会将所有原本应该放在栈中的Block全部放到堆中,所以这使得我们现在的讨论可以省去很大一部分的麻烦。下面我们就只讨论ARC环境下全局Block堆Block的内存管理。

首先,全局的Block比较简单,一句话就可以讲完:凡是没有引用到Block作用域外面的参数的Block都会放到全局内存块中,在全局内存块的Block不用考虑内存管理问题。(放在全局内存块是为了在之后再次调用该Block时能快速反应,当然没有调用外部参数的Block根本不会出现内存管理问题)。

所以Block的内存管理出现问题的,绝大部分都是在堆内存中的Block出现了问题。实际上属于Block特有的内存管理问题就只有一个:循环引用。

Block的循环引用是比较容易被忽视,原本也是相对比较难检查出来的问题。当然现在苹果在XCode编译的层级就已经做了循环引用的检查,所以这个问题的检查就突然变的没有难度了。

简单说一下循环引用出现的原理:Block的拥有者在Block作用域内部又引用了自己,因此导致了Block的拥有者永远无法释放内存,就出现了循环引用的内存泄漏。下面举个例子说明一下:

@interface ObjTest () {
    NSInteger testValue;
}
@property (copy, nonatomic) void (^block)();
@end

@implement ObjTest
- (void)function {
    self.block = ^() {
        self.testValue = 100;
    };
}
@end

在这个例子中,ObjTest拥有了一个名字叫block的Block对象;然后在这个Block中,又对ObjTest的一个成员变量testValue进行了赋值。于是就产生了循环引用:ObjTest->block->ObjTest。

至于如何打破循环引用,请参考这篇文章:http://www.jianshu.com/p/0a3759c93057

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言 Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这...
    小人不才阅读 9,138评论 0 23
  • 最近发现很多开发者对block的理解并不是很深,很多项目当中使用的时候多多少会有些问题,今天给大家详细讲讲bloc...
    tanyufeng阅读 12,852评论 17 60
  • block封装了一段代码,这段代码可以在任何时候执行。Block可以作为函数参数或者函数的返回值,而其本身又可以带...
    coderJerry01阅读 3,262评论 0 0
  • 一、前言: Block是Objective-C中的一项强大的特性,Block可以看作是OC中对于闭包函数的实现,实...
    Michael_Lee_阅读 9,952评论 2 17
  • Java的跨平台特性建立在Java虚拟机之上。 Java虚拟机在不同平台上有不同的版本,但是他们都能执行同一cla...
    趁现在赶快回家阅读 3,446评论 0 0