Objective-C中Block内存分配全解析

Block的类

设置对象的储存域
_NSConcreteStackBlock 栈区
_NSConcreteGlobalBlock 程序的数据区(全局区)
_NSConcreteMallocBlock 堆区


Block分配的规律

Block不论在ARC下还是在MRC下,都会视情况被分配到这三种区中。我总结了分配在各种区的条件,如下:

  • NSConcreteGlobalBlock:无论此block是否被持有,block内没有引用外部变量
  • NSConcreteStackBlock: 此block必须未被持有,并且引用了外部变量
  • NSConcreteMallocBlock:此block必须被持有,并且引用了外部变量

Block执行过copy后的情况

Block的类 副本源的配置储存域 复制效果
_NSConcreteStackBlock 栈区 从栈复制到堆
_NSConcreteGlobalBlock 全局区 什么也不做
_NSConcreteMallocBlock 堆区 引用计数增加


栈上的Block什么时候会被复制到堆

  • 调用Block的copy实例方法
  • Block作为函数返回值返回时
  • 将Block赋值给附有__strong修饰符id类型的类或Block类型成员变量时
  • 在方法名中含有usingBlockCocoa框架方法或Grand Central Dispatch的API中传递Block时

接下来就结合代码来分析Block的内存分配。

等号左侧在OC默认情况下属于强指针,用__weak修饰后变成弱指针,右侧Block不会被持有,并且Block引用了外部变量,所以会被分配在栈区

int temp = 10;
__weak void(^blk_t1)(void) = ^{
    NSLog(@"%d",temp);
};
NSLog(@"1===%@",blk_t1);

image.png


等号左侧在OC默认情况下属于强指针,右侧block被持有,引用外部变量就分配在堆区

int temp = 10;
void(^blk_t)(void) = ^{
    NSLog(@"%d",temp);
};
blk_t();
NSLog(@"2===%@",blk_t);

image.png


等号左侧在OC默认情况下属于强指针,右侧block被持有,不引用外部变量就分配在全局区

void(^blk_tt)(void) = ^{
        
};
NSLog(@"3===%@",blk_tt);

image.png


此block未被持有,且引用了外部变量,所以分配在栈区

int temp = 10;
NSLog(@"4===%@",^{
    NSLog(@"%d",temp);
});

image.png


栈区的block在执行copy后会被分配到堆区

int temp = 10;
NSLog(@"5===%@",[^{
    NSLog(@"%d",temp);
} copy]);

image.png


等号左侧在OC默认情况下属于强指针,右侧block被持有,block内部未引用外部变量,被分配到全局区,执行copy后依然在全局区

void (^blk_ttt)(void) = ^() {
    
};
blk_ttt();

NSLog(@"\n6===\n拷贝前%@\n拷贝后%@",blk_ttt,[blk_ttt copy]);

image.png


block使用内部局部变量,未引用外部变量,依然是全局block

void (^blk_tttt)(void) = ^{
    int b = 20;
    NSLog(@"%d",b);
};
blk_tttt();
NSLog(@"7===%@",blk_tttt);

image.png


block内部使用传进来的参数,并不会持有该参数,此block在使用了参数后依然是全局block

NSString *str = @"I love China!";
void (^blk_ttttt)(NSString *) = ^(NSString *param){
    NSLog(@"%@",param);
};
blk_ttttt(str);
NSLog(@"8===%@",blk_ttttt);
image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容