Block产生的内存泄露,以及解决方法
前言:
在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产生的内存泄露,以及解决方法的更多相关文章
- 分享.net常见的内存泄露及解决方法
分享.net常见的内存泄露及解决方法 关于内存泄漏的问题,之前也为大家介绍过,比如:<C++中内存泄漏的检测方法介绍>,是关于C++内存泄漏的.今天为大家介绍的是关于.NET内存泄漏的问题 ...
- 调用MediaScannerConnection 发生内存泄露的解决方法
调用MediaScannerConnection发起扫描时经常会发生内存泄露,例如: E ActivityThread: Activity FolderListActivity has leaked ...
- JS高程中的垃圾回收机制与常见内存泄露的解决方法
起因是因为想了解闭包的内存泄露机制,然后想起<js高级程序设计>中有关于垃圾回收机制的解析,之前没有很懂,过一年回头再看就懂了,写篇博客与大家分享一下. #内存的生命周期: 分配你所需要的 ...
- Android APP常见的5类内存泄露及解决方法
1.static变量引起的内存泄漏 因为static变量的生命周期是在类加载时开始 类卸载时结束,也就是说static变量是在程序进程死亡时才释放,如果在static变量中 引用了Activity 那 ...
- WPF不明内存泄露已解决,白头发也没了
原文:WPF不明内存泄露已解决,白头发也没了 在使用OpenExpressApp进行WPF应用开发过程中遇到多个内存泄漏的地方,在上一篇中求助了一个内存泄露问题[WPF不明内存泄露原因,头发都白了几根 ...
- Java常见的几种内存溢出及解决方法
Java常见的几种内存溢出及解决方法[情况一]:java.lang.OutOfMemoryError:Javaheapspace:这种是java堆内存不够,一个原因是真不够(如递归的层数太多等),另一 ...
- 【javascript】内存泄露及其解决办法
1.内存泄露:一般由于开发者使用不当导致不用的内存没有被操作系统或者空闲内存池回收释放. 2.造成内存泄露的常见原因: 1) 意外的全局变量引起的内存泄露 2)闭包引起的内存泄露 闭包可以维持函数内局 ...
- PF不明内存泄露已解决,白头发也没了(转)
在使用OpenExpressApp进行WPF应用开发过程中遇到多个内存泄漏的地方,在上一篇中求助了一个内存泄露问题[WPF不明内存泄露原因,头发都白了几根],本篇与大家分享一下如何解决此问题的过程. ...
- MyEclipse 2015 运行tomcat 内存溢出的解决方法
内存溢出错误: 2016-3-16 11:19:55 org.apache.catalina.core.StandardWrapperValve invoke严重: Servlet.service() ...
随机推荐
- HashMap和SparseArray的性能比较。
HashMap和SparseArray可以实现相似的功能. 但SparseArray是Android定义的,在键是整数时,他比HashMap的性能更高,因为HashMap使用的是Integer对象, ...
- React Native知识2-Text组件
Text用于显示文本的React组件,并且它也支持嵌套.样式,以及触摸处理.在下面的例子里,嵌套的标题和正文文字会继承来自styles.baseText的fontFamily字体样式,不过标题上还附加 ...
- Android Bitmap占用内存计算公式
Android对各分辨率的定义 当图片以格式ARGB_8888存储时的计算方式 占用内存=图片长*图片宽*4字节 图片长 = 图片原始长 (设备DPI/文件夹DPI) 图片宽 = 图片原始宽(设备D ...
- Starling中通过PivotX 和 PivotY 修改原点
一个显示对象的默认原点在左上角.addChild 是将它的左上角放在了父容器的(0, 0)位置. 如果将该显示对象的PivotX 和 PivotY 修改为其宽高的一半,那么它的原点就变到了该对象的中心 ...
- mac系统及xcode使用的SVN客户端安装升级
当前的SVN版本已经升级到1.8.x了,但mac系统自带的以及xcode使用的SVN客户端版本没有跟着升级,还是1.6.x的版本.为了解决隐藏目录.svn只在根目录下存在的情况,至少要升级到1.7.x ...
- ORA-00600: internal error code, arguments: [17281], [1001], [0x1FF863EE8], [], [], [], [], []
我们生产服务器中的一个数据库发出监控告警日志的邮件,内容如下所示,在31号09:11分出现了大名鼎鼎的ORA-00600错误. Dear All: The Instance xxx' alert lo ...
- SYMBDSNAP_SDK[3943]: Failed to open device: /dev/symbdsnapctl, errno: 2
在Linux的日志/var/log/message里面看到下面错误信息: Oct 26 09:48:42 xxxxxxx SYMBDSNAP_SDK[3943]: Failed to open dev ...
- Linux如何找出用户的创建时间
在Linux系统中,如何找到用户创建的时间呢? 其实是没有标准方法查找用户创建时间.下面再搜索了一些资料后,自己验证并测试了一下这些方法,仅供参考: 1:如果创建的用户有家目录,那么可以ls -l / ...
- C# Attribute学习
由于项目中需要使用到序列化相关的技术,从而想到是否可以使用C#中的特性,特此花了近两小时学习了一下. 对于特性的学习,主要参考了两篇博文,特此感谢.以下附链接: http://www.cnblogs. ...
- 一道常被人轻视的前端JS面试题
前言 年前刚刚离职了,分享下我曾经出过的一道面试题,此题是我出的一套前端面试题中的最后一题,用来考核面试者的JavaScript的综合能力,很可惜到目前为止的将近两年中,几乎没有人能够完全答对,并非多 ...