美文网首页
内存泄漏常见的几个情景

内存泄漏常见的几个情景

作者: 乜_啊_ | 来源:发表于2018-10-24 15:10 被阅读36次

主要是分享几个平时容易遇到的导致内存泄漏的情景,如果有遇到其它情景会继续补充,也欢迎大家提出来还有哪些常见的情景,如果有哪些理解错误的地方,也希望各位朋友能够支持,非常感谢。

1 .block循环引用.

情景:

self.animations = ^{

self.testArray= @[@"haha"];

    };

分析:

如上的代码所示:self对animations这个block强引用,block捕获了testArray对象,同样也对testArray持有强引用,而self对testArray也持有强引用。三者之间的引用:self -> animations -> testArray -> self。三者之间相互引用,引用计数无法变为0,导致内存泄漏。

解决方案:

1. 最常用的方法是使用对self使用__weak修饰, __weak typeof (self) weakSelf = self,代码如下

__weak typeof (self) weakSelf = self; 

 self.animations = ^{

weakSelf.testArray= @[@"haha"];

   };

注意:是不是使用weakSelf就万事大吉了呢?当然不是。如果在多线程下,使用weakSelf会出现什么情况呢?

在多线程下,在某一个线程中,对str做了一次release操作了,内存被销毁了,但是指针还没有被置nil。由于是多线程,在销毁的瞬间,同时又有其他线程在访问str这个对象,导致crash。(如果没有出现crash,可以加大循环的次数,改成1000)。

__weak MyViewController *wself = self;

    self.completionHandler = ^(NSInteger result) {

    [wself.property removeObserver: wself forKeyPath:@"pathName"];

};

那要怎么解决呢:但是使用__strongtypeof(weakSelf) strongSelf = weakSelf;这样一来,self 所指向对象的引用计数变成 2,即使主线程中的 self 因为超出作用于而释放,对象的引用计数依然为 1,避免了对象的销毁。

  __weak MyViewController *wself =self;

 self.completionHandler = ^(NSIntegerresult) {

    __strong  typeof(wself) sself = wself;// 强引用一次

    [sself.property removeObserver: sself forKeyPath:@"pathName"];

};

2. delegate循环引用

情景:

控制器a,视图b是控制器a的子视图。 b.delegate = a。

分析:

视图b是控制器a的子视图,a对b强引用,而b对delegate强引用。b.delegate=a,delegate对控制器a强引用。引用关系:a->b->delegate->a。

解决方案:

b的delegate使用weak修饰:@property (nonatomic, weak) id<BDelegate> delegate;

注意:不能使用assign代理weak,assign是修饰数值类型的变量的,因为基本数值类型是存在栈的,不需要手动管理内存。如果拿assign去修饰一个对象,会导致内存被销毁了,但是指针没有被置为nil,这个对象就会变成野指针,下次访问这个野指针的时候,谁也无法知道这个野指针是访问了什么样的内存,导致crash。

3. NSTimer没有销毁

[NSTimer timerWithTimeInterval:1 target:self selector:@selector(viewDidLoad) userInfo:nil repeats:YES];

系统为了保证定时器能够正常运行,会对target一直强引用,知道定时器结束。所以即使页面已经pop了,但是页面并没有被销毁。即使使用__weak typeof (self) weakSelf = self; target传weakSelf也没有用,因为系统会一直对这个target强引用。苹果的官方文档是这么说的:

那要怎么销毁呢?在不需要定时器的时候,关闭定时器,把定时器置nil

[_timer invalidate];//关闭定时器

  _timer = nil;//把定时器置nil

注意:不要在dealloc里面写着两句代码,因为_timer被循环引用着,压根就不会走到dealloc方法来。

4. 非OC对象内存处理,没有手动释放

对于一些非OC对象,使用完毕后其内存仍需要我们手动释放。

举个例子,比如获取图片的像素点方法中:

- (uint32_t*)pixelBRGABytesFromImageRef:(CGImageRef)imageRef {

    NSUInteger iWidth = CGImageGetWidth(imageRef);

    NSUInteger iHeight = CGImageGetHeight(imageRef);

    NSUIntegeriBytesPerPixel = 4;

    NSUIntegeriBytesPerRow = iBytesPerPixel * iWidth;

    NSUIntegeriBitsPerComponent = 8;

    uint32_t*pixels = (uint32_t*)malloc(iWidth * iHeight *sizeof(uint32_t));

     memset(pixels,0, iWidth * iHeight *sizeof(uint32_t));

    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();

    CGContextRef context = CGBitmapContextCreate(pixels,

                                                 iWidth,

                                                 iHeight,

                                                 iBitsPerComponent,

                                                 iBytesPerRow,

                                                 colorspace,

                                                 kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);

    CGRectrect =CGRectMake(0 , 0 , iWidth , iHeight);

    CGContextDrawImage(context , rect ,imageRef);

    CGColorSpaceRelease(colorspace);

    CGContextRelease(context);

    CGImageRelease(imageRef);

    return pixels;

}

在如上代码中的CGImageRef类型变量非OC对象,其需要手动执行释放操作CGImageRelease(imageRef)    CGColorSpaceRelease(colorspace); CGContextRelease(context),否则会造成大量的内存泄漏导致程序崩溃。其他的对于CoreFoundation框架下的某些对象或变量需要手动释放、C语言代码中的malloc等需要对应free等都需要注意。

5.循环体中多次创建对象,造成内存暴涨

如图所示,在一个很大的循环体中,创建临时数组(如果图片存的是大体积的data或者image),会导致内存暴涨。

解决方案:

可以在循环里内,创建一个@autoreleasepool{},临时变量的创建在@autoreleasepool{}里面,就能保证除了@autoreleasepool{}的作用域之后,临时变量会被及时销毁。

拓展

可是大家知道为什么使用__weak修饰就能避免循环引用?使用__weak修饰的对象,引用计数不会+1,这个对象会被加入到一个weak hash表中,以对象的内存地址a(假设内存地址为a)作为key,对象作为value,存到一个hash表中。当这个对象引用计数为0的时候,会通过key为a在hash表中寻找对象,找到对象之后把对象置为nil。

相关文章

  • 内存泄漏常见的几个情景

    主要是分享几个平时容易遇到的导致内存泄漏的情景,如果有遇到其它情景会继续补充,也欢迎大家提出来还有哪些常见的情景,...

  • Xcode调试工具

    一.静态内存分析工具 编译阶段查找内存泄漏等问题 1.常见内存泄漏问题 常见的内存泄漏除了循环引用,CoreFou...

  • 记录电商公司面试

    面试记录 问了常见的内存泄漏常见有哪些 Handler的内存泄漏情况 activity,window,view之间...

  • Android性能优化 内存泄漏和内存溢出

    内存泄漏 内存溢出 常见的内存泄露场景 常见的内存溢出场景

  • Android 内存泄漏

    内存泄漏的原因 常见的内存泄漏与解决方法 检测内存泄漏 认识内存泄漏 根本原因就是当一个对象理应被回收的时候,因为...

  • java 基础2

    1 java内存泄漏的几种情景 内存泄漏内存泄露是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及...

  • Android 内存泄漏(MemoryLeak)

    本片文章我们从以下几个方面来了解内存泄漏: 1、什么是内存泄漏 2、内存泄漏产生的原因有哪些 3、如何定位内存泄漏...

  • Android常见内存泄漏汇总

    目录:一、内存泄漏介绍二、常见内存泄漏场景1.单例导致内存泄露2.静态变量导致内存泄漏3.非静态内部类导致内存泄露...

  • 三个方法帮助解决Android内存泄漏问题

    三个方法帮助解决Android内存泄漏问题 最近自己遇到了好几个内存泄漏的问题,也帮同事解决了几个内存泄漏的问题记...

  • LeakCanary和常见内存泄漏场景

    LeakCanary和常见内存泄漏场景 一. LeakCanary介绍 1. 介绍 2. 用法 二. 常见泄漏方式...

网友评论

      本文标题:内存泄漏常见的几个情景

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