block 实现原理和相关内存管理详解
来源:互联网 发布:php多文件上传 编辑:程序博客网 时间:2024/06/09 15:20
本文转载自 OSCHINA “哥特复心” 的两篇文章:
block 实现原理详解(一)
block 实现原理(内存管理详解)(二)
感谢原作者的分享!
(一)block 实现原理
对于大多数人来讲,block内部到底是怎样实现的呢?我们可以借助clang将其编译成为c++的代码,就可以看出,block到底是什么东西,先来看这样一个问题,
<!-- lang: cpp --> int age = 10; void (^block)() = ^{ NSLog(@"%d",age); }; age = 30; block();//10
以及下面的这一段代码
<!-- lang: cpp --> __block int age = 10; void (^block)() = ^{ NSLog(@"%d",age); }; age = 30; block();//30
你会发现这两个结果是不同的,
第一个输出10,第二个输出的是30
要想知道这里面干了些什么!需要我们将其编译成为C++代码,看下里面到底搞了些什么?
使用终端,转到mian.m文件下,使用如下代码 clang -rewrite-objc main.m 将其编译生成 main.cpp文件
这时候,我们打开mian.cpp便知 在文件的最底下main函数中
<!-- lang: cpp -->int main(int argc, const char * argv[]){ /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; __attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0*)&age, 0, sizeof(__Block_byref_age_0), 10}; void (*block)() = (void (*)())&__main_block_impl_0((void *)__main_block_func_0,&__main_block_desc_0_DATA, (__Block_byref_age_0 *)&age, 570425344); (age.__forwarding->age) = 30; ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); } return 0;}
block内部是调用了一个结构体中的函数:
static struct main_block_desc_0 { size_t reserved; size_t Block_size; void (copy)(struct __main_block_impl_0, struct main_block_impl_0); void (dispose)(struct __main_block_impl_0*); }
然后经过分析该c++文件我们知道
block实际上是: 指向结构体的指针
编译器会将block的内部代码生成对应的函数
而在mian.m中,调用普通的int变量时,传过来的age其实是一个值传递,而__block则是引用传递!
所以,才是如上的结果!
这是对block的一个基础认识,下面我将介绍一下mrc和arc使用block的区别 !
(二)mrc和arc使用block的区别
在以前,MRC环境下,使用block很可能会出现内存泄漏问题,并且在以往的面试中,一些接触比较久的程序员都会喜欢问到这个问题,block内存泄漏的问题!
下面,我来介绍一下,MRC下Block内存泄漏的一个问题
先随意创建一个Dog类,并创建int类型age属性,
然后在main函数中,创建下列代码,
import “Dog.h”int main(int argc, const char * argv[]) { @autoreleasepool { Dog *d = [[Dog alloc] init]; d.age = 20 ; void(^block)() = ^{ NSLog(@"%d",d.age); }; block(); [d release]; }}
这个时候是正常情况,但是,如果添加如下第10行代码:
import “Dog.h”int main(int argc, const char * argv[]) { @autoreleasepool { Dog *d = [[Dog alloc] init]; d.age = 20 ; void(^block)() = ^{ NSLog(@"%d",d.age); }; Block_copy(block); block(); [d release]; }}
此时此刻,有人想对block进行release,但是不管你是否对block进行release ,都无法释放d对象。为什么呢??
这个时候,我们就要对block进行分析了:
1.默认情况下, block的内存是在栈中
- 它不会对所引用的对象进行任何操作
2.如果对block做一次copy操作, block的内存就会在堆中
- 它会对所引用的对象做一次retain操作
- 非ARC : 如果所引用的对象用了__block修饰, 就不会做retain操作
- ARC : 如果所引用的对象用了__unsafe_unretained__weak修饰, 就不会做retain操作
所以,只需要在Dog类前面加上__block即可!
- block 实现原理和相关内存管理详解
- block 实现原理(内存管理详解)
- block 实现原理(内存管理详解)(二)
- 内存管理和 Block
- block实现原理详解
- block 实现原理详解
- Block和变量,内存管理
- Block使用方法及内存管理详解
- iOS内存管理---block机制详解
- iOS学习之Block内存管理详解
- iOS Block原理和内存中位置
- iOS笔记 Block和内存管理
- iOS Block底层实现原理详解
- block 实现原理详解(一)
- 简述内存管理的原理和其简单实现
- 【Objective-C高级编程】iOS与OS X多线程和内存管理(四) Block的实现
- 内存管理原理和分类
- unity 内存管理和原理
- Html5多浏览器支持情况
- 五大常用算法之五:分支限界法
- Android中Paint的相关用法
- Lucky - HDU 5213 莫队算法
- 产品经理常犯的10个错误
- block 实现原理和相关内存管理详解
- Oracle 实例性能分析与优化之AWR学习总结
- Android中项目中各个文件夹的含义和用途详解
- jquery 初步(五) 可见和隐藏过滤器
- Effective C++ 条款02解读: 尽量以const, enum, inline替换#define
- 不要执行用utf-8編碼,并且內容包含非拉丁字符的批处理脚本
- Android UI之自定义——类似iOS的Tabbar
- android adb 读写模式 挂载文件系统
- hdu 1212 Big Number