44 (OC)* 内存泄漏、什么情况下会出现内存泄漏、野指针、空指针、nil、NSNull、(僵尸对象、野指针、bad_access )

问题:

1:空指针、野指针、内存泄漏、常见的内存泄漏有哪些?怎样检测和防止内存泄漏

2:nil、Nil、NULL、NSNull的区别 

3:bad_access 僵尸对象

一:内存泄漏

程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果

1:常见的内存泄漏情况

1:对象之间的循环引用问题
循环引用的实质:多个对象相互之间有强引用,不能施放让系统回收。解决办法:使用 weak 打破对象之间的相互强引用。

2:block的循环引用
blockcopy时都会对block内部用到的对象进行强引用的。解决办法使用:使用__weak打破循环的方法只在 ARC下才有效,在 MRC 下应该使用__block。

  __weak typeof(self) weakSelf = self; self.myBlock = ^() { // 除了下面的还有 调用 self的一些属性等等 [weakSelf doSomething] };

3: delegate 的循环引用
delegate是委托模式.委托模式是将一件属于委托者做的事情,交给另外一个被委托者来处理,在这里我们可能会出现委托者和被委托人之间的相互强引用问题;解决办法:在声明 delegate 属性的时候 用weak 进行弱引用 或者 通过中间对象(代理对象)的方式来解决(效率更加高的中间对象NSProxy:不需要进行发送消息和再动态解析,直接进行消息转发)

@property(nonatomic, weak) id delegate;

4:CADisplayLinkNSTimer会对target产生强引用,

如果target又对它们产生强引用,那么就会引发循环引用;解决办法:NSTimer 有一个block的方法,我们可以利用block的弱指针来解决__weak typeof(self) weakSelf = self;传 weakSelf 进去

5:通知的循环引用
iOS9 以后,一般的通知,都不再需要手动移除观察者,系统会自动在dealloc 的时候调用 [[NSNotificationCenter defaultCenter] removeObserver: self]iOS9 以前的需要手动进行移除。原因是:iOS9 以前观察者注册时,通知中心并不会对观察者对象做 retain 操作,而是进行了 unsafe_unretained 引用,所以在观察者被回收的时候,如果不对通知进行手动移除,那么指针指向被回收的内存区域就会成为野指针,这时再发送通知,便会造成程序崩溃。从 iOS9 开始通知中心会对观察者进行 weak 弱引用,这时即使不对通知进行手动移除,指针也会在观察者被回收后自动置空,这时再发送通知,向空指针发送消息是不会有问题的。建议最好加上移除通知的操作:

-(void)dealloc {
     [[NSNotificationCenter defaultCenter] removeObserver:self.observer name:@"name" object:nil]; 
}

6:WKWebView 造成的内存泄漏
总的来说,WKWebView 不管是性能还是功能,都要比 UIWebView 强大很多,本身也不存在内存泄漏问题,但是,如果开发者使用不当,还是会造成内存泄漏。请看下面这段代码:

@property(nonatomic, strong) WKWebView * wkWebView;

-(void) webviewMemoryLeak {
    WKWebViewConfiguration * config = [
        [WKWebViewConfiguration alloc] init
    ];
    config.userContentController = [
        [WKUserContentController alloc] init
    ];
    [config.userContentController addScriptMessageHandler: self name: @ "WKWebViewHandler"];
    _wkWebView = [
        [WKWebView alloc] initWithFrame: self.view.bounds configuration: config
    ];
    _wkWebView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview: _wkWebView];
    NSURLRequest * requset = [NSURLRequest requestWithURL: [NSURL URLWithString: @ "[https://www.baidu.com](https://www.baidu.com/)"]];
    [_wkWebView loadRequest: requset];
}
// 这样看起来没有问题, 但是其实“ addScriptMessageHandler” 这个操作, 导致了 wkWebView 对 self 进行了强引用, 然后“ addSubview” 这个操作, 也让 self 对 wkWebView 进行了强引用, 这就造成了循环引用。 解决方法就是在合适的机会里对“ MessageHandler” 进行移除操作:

-(void) viewDidDisappear: (BOOL) animated {
        [super viewDidDisappear: animated];
        [_wkWebView.configuration.userContentController removeScriptMessageHandlerForName: @ "WKWebViewHandler"];
    }

2:内存泄漏的查询

 

1:Analyze 静态分析 (command + shift + b)也就是编译,主要分析以下四种问题:

 

  1. 逻辑错误:访问空指针或未初始化的变量等;
  2. 内存管理错误:如内存泄漏等;
  3. 声明错误:从未使用过的变量;
  4. Api调用错误:未包含使用的库和框架。

 

2:Instruments中的Leak动态分析内存泄漏,product->profile ->leaks 打开工具主窗口

 

 

3:Facebook早已开源了一款检测内存问题的三方库FBRetainCycleDetector

3: 空指针 

没有存储任何内存地址的指针就称为空指针(NULL指针)。

被赋值为nil的指针,在没有被具体初始化之前,为nil。nil、Nil、NULL、NSNULL的含义和区别 

    nil:OC中的实例对象的空指针

    Nil:OC中类的空指针

    NULL:C类型的空指针

    NSNull:数值类的空对象野指针 ,存储类的NSArray、NSDictionary中的存储的空值。nil或NULL不能做为加到其中

注意:判断对象是否为空(nil、NSNil、@""、@(0) 以上4种)

@interface NSObject (CF)

/**
 *  判断对象是否为空
 *  常见的:nil、NSNil、@""、@(0) 以上4种返回YES
 *  如果需要判断字典与数组,可以自行添加
 *  @return YES 为空  NO 为实例对象
 */
+ (BOOL)isEmpty:(id)object;

@end

@implementation NSObject (CF)

+ (BOOL)isEmpty:(id)object{
    if (object == nil || [object isEqual:[NSNull null]]) {
        return YES;
    } else if ([object isKindOfClass:[NSString class]]) {
        return [object isEqualToString:@""];
    } else if ([object isKindOfClass:[NSNumber class]]) {
        return [object isEqualToNumber:@(0)];
    }
    return NO;
}
@end

4:野指针

    不是nil指针,是指向"垃圾"内存(不可用内存 如:内存被销毁的时候)的指针。 

    它所指向的内存空间已经被释放,而没有置空,我们也没法访问,给他发送消息会崩溃。

  给空指针发送消息不会崩溃。

3:僵尸对象、野指针、EXC_BAD_ACCESS

僵尸对象:内存已经被回收的对象, 但是还是有指针指向该区域。

野指针:指向僵尸对象的指针,向野指针发送消息会导致崩溃。

野指针错误形式在Xcode中通常表现为:EXC_BAD_ACCESS,因为你访问了一块已经不属于你的内存。 

1:全局断点调试

用全局断点,看是否可以定位到错误的位置。如图设置一下就OK了。有的时候是可以直接定位到出错的代码位置。

2:Xcode中,可以开启僵尸对象模式。

 

 3:分析-Analyze

使用Xcode来分析你的项目,从Xcode的 Product菜单选择 Analyze或按 Shift-Command-B.Xcode的将需要片刻的时间,但是当它完成的时候你会在左边的 Issue Navigator看到问题列表。由Analyze发现的问题用蓝色高亮显示。

当你点击一个问题,Xcode的会指向问题代码块,这些正是你要的注意的地方。注意,Xcode仅仅是建议。在某些情况下,这是可能的,问题是不相关的,不固定。

 

 4:使用Instruments-Zombies检测

 

 

 

posted on 2018-07-17 11:09  风zk  阅读(306)  评论(0编辑  收藏  举报

导航