美文网首页
内存泄漏可能存在在哪些地方

内存泄漏可能存在在哪些地方

作者: Zz7777777 | 来源:发表于2017-05-23 14:23 被阅读74次

由于前段时间我负责的app 严重发热,由于上线时间短,所以出现了一些问题 结合网上一些教程我这边也仔细检查,检查的结果原因如下。可能有些地方写得不对,大神勿喷,请订正.传送门

1.Block循环引用问题

在苹果使用ARC管理之前,Block的内存管理(block如何进行内存管理的)需要区分是Global(全局)、Stack(栈)还是Heap(堆)。而在使用了ARC之后,苹果自动会将所有原本应该放在栈中的Block全部放到堆中,所以这使得我们现在的讨论可以省去很大一部分的麻烦。下面我们就只讨论ARC环境下全局Block和堆Block的内存管理。

Block的循环引用是比较容易被忽视,原本也是相对比较难检查出来的问题。当然现在苹果在XCode编译的层级就已经做了循环引用的检查,所以这个问题的检查就突然变的没有难度了。简单说一下循环引用出现的原理:Block的拥有者在Block作用域内部又引用了自己,因此导致了Block的拥有者永远无法释放内存,就出现了循环引用的内存泄漏

@interface ObjTest () {

NSInteger testValue;

}

@property (copy, nonatomic) void (^block)();

@end

@implement ObjTest

- (void)function {

self.block = ^() {

self.testValue = 100; 这里就会发生内存泄漏问题

  };

}

@end

ObjTest拥有了一个名字叫block的Block对象;然后在这个Block中,又对ObjTest的一个成员变量testValue进行了赋值。于是就产生了循环引用:ObjTest->block->ObjTest。

要避免循环引用的关键就在于破坏这个闭合的环。在目前只考虑ARC环境的情况下,笔者所知的只有一种方法可以破坏这个环:在Block内部对拥有者使用弱引用。

@interfaceObjTest () {

NSInteger testValue;

}

@property (copy, nonatomic)void(^block)();

@end

@implement ObjTest

- (void)function {

__weak ObjTest* weakSelf =self;

self.block= ^() {weakSelf.testValue=100;

};

}@end

在Block外创建一个对于self的弱引用,然后在Block内引用self的地方全部使用这个弱引用。这样就使得Block内部不会对self本身做引用计数+1的操作。那样就可以打破循环引用的环了。

2.AFN框架和MJRefresh上下拉刷新(其实都是block引发的命案)

在封装网络请求类时需注意的是需要将请求队列管理者AFHTTPSessionManager声明为单例创建形式。对于该问题,AFNetWorking的作者在gitHub上也指出建议使用者在相同配置下保证AFHTTPSessionManager只有一个,进行全局管理,因此我们可以通过单例形式进行解决。下方展示部分核心代码:

然后在说MJRefresh(参考:传送门)

一般的我们是怎么使用MJRefresh 这个玩意的 看代码

self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{

self.page =1;       

[self.dataArr removeAllObjects];       

[self loadData];

}];

若在MJRefresh的执行Block中调用当前self或其所属属性,一定要注意循环引用问题。我们简单分析下MJRefresh为什么会造成循环引用问题:点击进入headerWithRefreshingBlock对应方法即可

#pragmamark- 构造方法

+ (instancetype)headerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock{   

MJRefreshHeader *cmp= [[selfalloc] init];

cmp.refreshingBlock= refreshingBlock;

return cmp;

}

这里仅有三行代码,无非就是创建了下拉刷新部分View然后返回,这里比较重要的是cmp.refreshingBlock = refreshingBlock;这一句,这里的refreshingBlock是属于MJRefreshHeader的强引用属性,最后header会成为我们自己tableView的强引用属性mj_header,也就是说self.tableView强引用header, header强引用refreshingBlock,如果refreshingBlock里面强引用self,就成了循环引用,所以必须使用weakSelf,破掉这个循环.如何解决直接看传送们.

3.大次数循环内存暴涨问题(你永远都不知道会存在这里的内存泄漏)

for(inti =0; i <100000; i++) {

 NSString *string= @"Abc";

string= [string lowercaseString];

string= [stringstringByAppendingString:@"xyz"];  //引起内存飙涨  

NSLog(@"%@",string);

}

该循环内产生大量的临时对象,直至循环结束才释放,可能导致内存泄漏,解决方法为在循环中创建自己的autoReleasePool(autoReleasePool都干了啥,这么🐂),及时释放占用内存大的临时变量,减少内存占用峰值。

for(inti =0; i < 100000; i++) {

@autoreleasepool{            

NSString *string= @"Abc";

string= [stringlowercaseString];string= [stringstringByAppendingString:@"xyz"];

NSLog(@"%@",string);}    

}

附、如何检测App的内存泄漏问题

1、借助Xcode自带的Instruments工具(选取真机测试)

2、简单暴力的重写dealloc方法,加入断点或打印判断某类是否正常释放。

3、通过Facebook出品的FBMemoryProfiler工具类进行检测,感兴趣的童鞋可进行了解。

4、更多关于如何进行app性能优化请看:微信读书 iOS 性能优化总结    MLeaksFinder简介

相关文章

  • 内存泄漏可能存在在哪些地方

    由于前段时间我负责的app 严重发热,由于上线时间短,所以出现了一些问题 结合网上一些教程我这边也仔细检查,检查的...

  • 内存泄漏分析

    1、内存泄漏判断 在Android Device Monitor工具中选中可能存在内存泄漏的进程(连接设备后获取r...

  • jvm内存泄漏问题排查分析笔记

    当发现服务器可能存在内存泄漏时(怎么发现?频繁gc但是堆内存降不下来,进程内存爆了就有可能是发生内存泄漏了),怎么...

  • 了解js内存泄漏

    原文链接 what 什么是内存泄漏:任何对象在您不再拥有或需要它之后仍然存在 内存泄漏的影响:不当清理的对象可能会...

  • 如何避免JS内存泄漏?

    很多开发者可能平时并不关心自己维护的页面是否存在内存泄漏,原因可能是刚开始简单的页面内存泄漏的速度很缓慢,在造成严...

  • 内存泄漏

    什么是内存泄漏?内存泄漏指任何对象在您不再拥有或需要它之后仍然存在 哪些操作会造成内存泄漏?1、垃圾回收器定期扫描...

  • Android内存泄漏测试小结

    内存泄漏小结 使用dumpsys分析内存泄漏 举例:分析微视粉丝列表activity是否存在内存泄漏 第一步:打开...

  • Javascript中常见的内存泄漏

    内存泄漏:内存泄漏指由于错误或疏忽导致程序未能释放已经不再使用的内存,内存泄漏并非内存在物理上的消失,而是应用程序...

  • 解决NSTimer、CADisplaylink的内存泄漏

    我们在NSTimer或者CADisplayLink的时候,如果使用不当,可能导致内存泄漏问题,至于内存泄漏的原因,...

  • 消除过期的对象引用

    你能看出以下代码哪里内存泄漏吗? 答案是: pop()方法存在内存泄漏。 内存泄漏可以称为“ 无意识的对象保持(u...

网友评论

      本文标题:内存泄漏可能存在在哪些地方

      本文链接:https://www.haomeiwen.com/subject/vgawxxtx.html