前言:

在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. Oracle a Parameter with multi value

     备注:此两种方案,都因为oracle内部字符函数的参数长度4000限制.另外,个人测试,性能不如”将数据插入物理表再JOIN查询“或”每1000次ID做一次IN查询“的总的运行速度. 即ID的个数越 ...

  2. UIToolBar

    //UIToolBar 是导航控制器默认隐藏的工具条 //设置UIToolBar的隐藏状态 self.navigationController.toolbarHidden = NO; //如何找到UI ...

  3. 【原+转】创建CocoaPods私有podspec

    在我的上一篇文章<iOS 手把手教你发布代码到CocoaPods>中着重介绍如何将自己的代码索引添加到公开的CocoaPods中,当你需要主动地向大众开源你的代码时需要那么做.但在现实中我 ...

  4. c++ 奇特的递归模板模式(CRTP)

    概述 使用派生类作为模板参数特化基类. 与多态的区别 多态是动态绑定(运行时绑定),CRTP是静态绑定(编译时绑定) 在实现多态时,需要重写虚函数,因而这是运行时绑定的操作. CRTP在编译期确定通过 ...

  5. 深圳 Maker Faire 2016 & Microsoft Booth

    首先,感谢Hackster.io和微软,因为发表在Hackster.io的项目<A fall detection system based on Arduino, Windows and Azu ...

  6. Linux 平台MySQL启动关闭方式总结

    MySQL的启动方法有很多种,下面对比.总结这几种方法的一些差异和特性,下面实验的版本为MySQL 5.6.如有疏漏或不足,敬请指点一二.   1:使用mysqld启动.关闭MySQL服务 mysql ...

  7. SQL SERVER 2000通过链接服务器发送邮件出现错误

    案例环境: 服务器A系统: Windows Server 2000 数据库版本 : Microsoft SQL Server  2000 - 8.00.2282 (Intel X86) 服务器B系统: ...

  8. .NET重构(类型码的设计、重构方法)

    阅读目录: 1.开篇介绍 2.不影响对象中的逻辑行为(枚举.常量.Entity子类来替代类型码) 3.影响对象中的逻辑行为(抽象出类型码,使用多态解决) 4.无法直接抽象出类型码(使用策略模式解决) ...

  9. 设计模式C#实现(十三)——享元模式(蝇量模式)

    意图 0 适用性 1 结构 2 实现 3 效果 4 参考 5 意图 运用共享技术有效地支持大量细粒度的对象. 适用性 当以下情况都成立时使用: 一个程序使用了大量的对象 完全由于使用大量对象造成很大存 ...

  10. 【转】深入理解SQL的四种连接-左外连接、右外连接、内连接、全连接

    [原文]:http://www.jb51.net/article/39432.htm 1.内联接(典型的联接运算,使用像 =  或 <> 之类的比较运算符).包括相等联接和自然联接.    ...