前言:

在ARC(自动引用技术)前,Objective-c都是手动来分配释放 释放 计数内存,其过程非常复杂。

ARC技术推出后,貌似世界和平了很多,但是其实ARC并不等同于Java或者C#中的垃圾回收,ARC计数只是在XCode在编译的时候自动帮我们加上了释放 计数+1 计数-1.

内存泄露例子:

然而在一些特殊的情况下,内存泄露依然存在,而且防不慎防,这里讲一下Objective-C中Block计数是如何产生内存泄露的,如下代码

.h中

typedef void (^CompletionBlock)(NSString *aStr);
@interface B : NSObject
@property (copy) CompletionBlock completionBlock;
@property (copy) NSString *str;
@end

  

.m中

@implementation B
-(id)init{
self = [super init];
if(self){
self.str = @"init string value";
}
return self;
} -(void)doAction
{
__block B *b1 = self;
self.completionBlock = ^(NSString *aStr){
b1.str = aStr;
};
self.completionBlock(@"new string value");
} -(void)dealloc{
NSLog(@"dealloc B");
}
@end

  

main函数中

B *b = [[B alloc]init];
[b doAction];
b = nil;//这句有和无其实无所谓

上面的程序看似没有问题,但是实际上对象b永远无法释放,原因在于doAction函数,这个函数里面有一个block函数名为completionBlock ,也就是一个函数指针。这个函数指针在调用的时候有使用一个对象,也就是self对象。但是这个block隐形的做了一件事情——将self引用计数+1了,因此这个时候self对象(也就是main函数中的b对象)的引用计数是2,这个时候即使我执行了b=nil,也无法释放,因为b=nil只是将计数减1了,而真正释放的唯一条件是引用计数为0。这就是所谓的Block的循环引用。

如何解决:

所以在使用block技术的时候,需要格外小心。有几个解决方法

approach 1: 让block里面的self的引用计数不要+1,这个时候做法是将"   __block B *b1 = self;"这一行改为,"  __weak __block B *b1 = self;",表示说“我block里面虽然会用到self,但是别担心,我不会讲引用计数+1的”

approach 2:在doAction函数内存的最后一行添加 self.completionBlock=nil;  因为block内部将self计数+1了,但是如果这个block自己先消亡,那么与之相关的一切都讲消亡(当然对于引用计数大于1的对象,不会消亡,只会计数减1)。

附加:

PS:开发中,几乎每个.m文件都会用到block技术,但是从未发现和在意这个内存泄露问题,这并不是XCode编译时的优化,而是我们所用到的Block技术(例如AFNetwork GCD Animation)中的block都是匿名Block——即,用完自动释放。 如果有一天不用匿名block就需要注意这个问题了。

例如下面的例子中,虽然使用了Block,但是没有泄露,是因为这是一个匿名的Block(即匿名函数指针)

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
self.view.backgroundColor = [UIColor redColor];
});

  

Block产生的内存泄露,以及解决方法的更多相关文章

  1. 分享.net常见的内存泄露及解决方法

    分享.net常见的内存泄露及解决方法 关于内存泄漏的问题,之前也为大家介绍过,比如:<C++中内存泄漏的检测方法介绍>,是关于C++内存泄漏的.今天为大家介绍的是关于.NET内存泄漏的问题 ...

  2. 调用MediaScannerConnection 发生内存泄露的解决方法

    调用MediaScannerConnection发起扫描时经常会发生内存泄露,例如: E ActivityThread: Activity FolderListActivity has leaked ...

  3. JS高程中的垃圾回收机制与常见内存泄露的解决方法

    起因是因为想了解闭包的内存泄露机制,然后想起<js高级程序设计>中有关于垃圾回收机制的解析,之前没有很懂,过一年回头再看就懂了,写篇博客与大家分享一下. #内存的生命周期: 分配你所需要的 ...

  4. Android APP常见的5类内存泄露及解决方法

    1.static变量引起的内存泄漏 因为static变量的生命周期是在类加载时开始 类卸载时结束,也就是说static变量是在程序进程死亡时才释放,如果在static变量中 引用了Activity 那 ...

  5. WPF不明内存泄露已解决,白头发也没了

    原文:WPF不明内存泄露已解决,白头发也没了 在使用OpenExpressApp进行WPF应用开发过程中遇到多个内存泄漏的地方,在上一篇中求助了一个内存泄露问题[WPF不明内存泄露原因,头发都白了几根 ...

  6. Java常见的几种内存溢出及解决方法

    Java常见的几种内存溢出及解决方法[情况一]:java.lang.OutOfMemoryError:Javaheapspace:这种是java堆内存不够,一个原因是真不够(如递归的层数太多等),另一 ...

  7. 【javascript】内存泄露及其解决办法

    1.内存泄露:一般由于开发者使用不当导致不用的内存没有被操作系统或者空闲内存池回收释放. 2.造成内存泄露的常见原因: 1) 意外的全局变量引起的内存泄露 2)闭包引起的内存泄露 闭包可以维持函数内局 ...

  8. PF不明内存泄露已解决,白头发也没了(转)

    在使用OpenExpressApp进行WPF应用开发过程中遇到多个内存泄漏的地方,在上一篇中求助了一个内存泄露问题[WPF不明内存泄露原因,头发都白了几根],本篇与大家分享一下如何解决此问题的过程. ...

  9. MyEclipse 2015 运行tomcat 内存溢出的解决方法

    内存溢出错误: 2016-3-16 11:19:55 org.apache.catalina.core.StandardWrapperValve invoke严重: Servlet.service() ...

随机推荐

  1. iOS屏幕尺寸和分辨率了解

    1.截至目前为止,主流的iOS设备屏幕有以下几种: ---------------  iPhone  ---------- --------  iPad ------------ 2.iOS设备屏幕分 ...

  2. Git 常见的命令操作

    克隆                git clone git地址 查看分支         git branch 查看git库状态  git status 切换分支         git  che ...

  3. iOS Class 使用NSProxy和NSObject设计代理类的差异

    经常发现在一些需要使用消息转发而创建代理类时, 不同的程序员都有着不同的使用方法, 有些采用继承于NSObject, 而有一些采用继承自NSProxy. 二者都是Foundation框架中的基类, 并 ...

  4. SQL SERVER特殊行转列案列一则

    今天有个同事找我,他说他有个需求,需要进行行转列,但是又跟一般的行转列有些区别,具体需求如下所说,需要将表1的数据转换为表2的显示格式. 我想了一下,给出了一个解决方法,具体如下所示(先给出测试数据) ...

  5. Topshelf 创建windows服务注意事项

    其中项目应该是控制台应用程序 test.exe需要赋与管理员权限,右键属性可以定义. test.exe  install test.exe unstall

  6. W3School-CSS 表格实例

    CSS 表格实例 CSS 实例 CSS 背景实例 CSS 文本实例 CSS 字体(font)实例 CSS 边框(border)实例 CSS 外边距 (margin) 实例 CSS 内边距 (paddi ...

  7. Mvc model验证总结

    Model 验证总结 Model 验证总结 1 一.Model 验证标记 1 1.启用客户端验证: 1 2.在 Model 中加入验证标记 2 3 . Model 类中可以添加的验证标记: 3 3.1 ...

  8. java实现excel模板导出

    一. 准备工作 1. 点击此下载相关开发工具 2. 将poi-3.8.jxls-core-1.0两个jar包放到工程中,并引用 3. 将excel模板runRecord.xls放到RunRecordB ...

  9. 【C++】输入多行数字到数组

    前天做某公司笔试题的时候,其输入格式是多行数字,每行以空格为分隔符,以换行符号为结束输入到多个数组.在JAVA中有相应的函数直接将一行拆成数组,感觉在C++中这中输入方式还是挺奇怪的,今天想出一种解决 ...

  10. linux

    托瓦兹跟BBS上面一堆工秳师一样, 他发现Minix虽然真癿很棒,但是谭宁邦教授就是丌愿意迚行功能癿加强,导致一堆工秳师在操作系统功能上面癿欲求丌满! 这个时候年轻癿托瓦兹就想:『既然如此,那我何丌自 ...