iOS DeveloperiOS进阶之路

iOS内存泄露&&检测

2017-08-16  本文已影响134人  li_礼光

内存泄露:

一个对象被其他对象强引用,在本来该作用域结束之后释放调用(dealloc),但是没有得到释放(dealloc未执行).

引起内存泄露的常见原因有哪些?

参考这篇博文 : iOS内存泄漏的常见情况,其中最常见的应该是对象之间相互引用,block和代理了.


序言 :

 #define TLog(prefix,Obj) {NSLog(@"对象内存地址:%p, 对象本身:%p, 指向对象:%@, --> %@",&Obj,Obj,Obj,prefix);}
#import "Obj_A.h"
#import "Obj_B.h"
具体查看 Obj A dealloc是否有调用?什么时候调用?

对象之间强引用

__weak和__strong的理解

验证方法一 :

- (void)objProblem1 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj_a = [[Obj_A alloc]init];
    Obj_B *obj_b = [[Obj_B alloc]init];
    obj_a.obj = obj_b;
    obj_b.obj = obj_a;
    NSLog(@"最简单的例子");
    NSLog(@"这里面对象A应用对象B,对象B引用对象A,两者之间相互强应用.所以会导致内存泄露");
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印结果

2017-08-16 15:41:57.594 MemoryLeak[21241:695251] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:41:57.595 MemoryLeak[21241:695251] 最简单的例子
2017-08-16 15:41:57.595 MemoryLeak[21241:695251] 这里面对象A应用对象B,对象B引用对象A,两者之间相互强应用.所以会导致内存泄露
2017-08-16 15:41:57.595 MemoryLeak[21241:695251] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

也就是方法结束之后,dealloc并没有被执行,也就是对象没有被释放

循环引用 信息定位

验证方法二 :

- (void)objProblem2 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    NSLog(@"__weak会不会改善内存泄漏问题?");
    Obj_A *obj_a = [[Obj_A alloc]init];
    Obj_B *obj_b = [[Obj_B alloc]init];
    __weak typeof(obj_a) weakObjA = obj_a;

    TLog(@"obj_a", obj_a);
    TLog(@"obj_b", obj_b);
    TLog(@"weakObjA", weakObjA);

    weakObjA.obj = obj_b;
    obj_b.obj = weakObjA;
    
    NSLog(@"weakObjA设置为nil");

    weakObjA = nil;
    TLog(@"obj_a", obj_a);
    TLog(@"obj_b", obj_b);
    TLog(@"weakObjA", weakObjA);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");

}

打印结果

2017-08-16 15:43:54.705 MemoryLeak[21264:696548] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] __weak会不会改善内存泄漏问题?
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] 对象内存地址:0x7fff5ad8c9b8, 对象本身:0x60800003f4e0, 指向对象:<Obj_A: 0x60800003f4e0>, --> obj_a
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] 对象内存地址:0x7fff5ad8c9b0, 对象本身:0x60800001f6c0, 指向对象:<Obj_B: 0x60800001f6c0>, --> obj_b
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] 对象内存地址:0x7fff5ad8c9a8, 对象本身:0x60800003f4e0, 指向对象:<Obj_A: 0x60800003f4e0>, --> weakObjA
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] weakObjA设置为nil
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] 对象内存地址:0x7fff5ad8c9b8, 对象本身:0x60800003f4e0, 指向对象:<Obj_A: 0x60800003f4e0>, --> obj_a
2017-08-16 15:43:54.707 MemoryLeak[21264:696548] 对象内存地址:0x7fff5ad8c9b0, 对象本身:0x60800001f6c0, 指向对象:<Obj_B: 0x60800001f6c0>, --> obj_b
2017-08-16 15:43:54.707 MemoryLeak[21264:696548] 对象内存地址:0x7fff5ad8c9a8, 对象本身:0x0, 指向对象:(null), --> weakObjA
2017-08-16 15:43:54.707 MemoryLeak[21264:696548] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

这里参考了iOS开发中本人或同事碰到的内存泄漏及解决办法里面提到的截图代码.发现这样子使用__weak的话对内存泄露是没有解决的.也用leaks检查了好几遍,同样是发现有内存泄露.

测试验证

验证方法三 :

- (void)objProblem3 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __weak Obj_A *weakObj = obj;

    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);
    
    void(^testBlock)() = ^(){
        TLog(@"weakObj - block", weakObj);
    };
    testBlock();
    NSLog(@"obj设置为nil");
    obj = nil;
    TLog(@"obj", obj);
    testBlock();
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印结果

2017-08-16 15:49:35.503 MemoryLeak[21319:699719] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:49:35.503 MemoryLeak[21319:699719] 对象内存地址:0x7fff53d6e9b8, 对象本身:0x6180000293c0, 指向对象:<Obj_A: 0x6180000293c0>, --> obj
2017-08-16 15:49:35.503 MemoryLeak[21319:699719] 对象内存地址:0x7fff53d6e9b0, 对象本身:0x6180000293c0, 指向对象:<Obj_A: 0x6180000293c0>, --> weakObj
2017-08-16 15:49:35.503 MemoryLeak[21319:699719] 对象内存地址:0x618000048ae0, 对象本身:0x6180000293c0, 指向对象:<Obj_A: 0x6180000293c0>, --> weakObj - block
2017-08-16 15:49:35.503 MemoryLeak[21319:699719] obj设置为nil
2017-08-16 15:49:35.504 MemoryLeak[21319:699719] Obj A dealloc
2017-08-16 15:49:35.504 MemoryLeak[21319:699719] 对象内存地址:0x7fff53d6e9b8, 对象本身:0x0, 指向对象:(null), --> obj
2017-08-16 15:49:35.504 MemoryLeak[21319:699719] 对象内存地址:0x618000048ae0, 对象本身:0x0, 指向对象:(null), --> weakObj - block
2017-08-16 15:49:35.504 MemoryLeak[21319:699719] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

总结 :

验证方法四 :

__strong关键字

- (void)objProblem4 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __weak Obj_A *weakObj = obj;

    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);
    
    void(^testBlock)() = ^(){
        __strong Obj_A *strongObj = weakObj;
        TLog(@"weakObj - block", weakObj);
        TLog(@"strongObj - block", strongObj);
    };
    
    testBlock();
    NSLog(@"obj设置为nil");
    obj = nil;
    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);

    testBlock();
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印结果

2017-08-16 15:52:19.971 MemoryLeak[21368:701529] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:52:19.971 MemoryLeak[21368:701529] 对象内存地址:0x7fff5e5d99b8, 对象本身:0x600000031b20, 指向对象:<Obj_A: 0x600000031b20>, --> obj
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] 对象内存地址:0x7fff5e5d99b0, 对象本身:0x600000031b20, 指向对象:<Obj_A: 0x600000031b20>, --> weakObj
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] 对象内存地址:0x600000240320, 对象本身:0x600000031b20, 指向对象:<Obj_A: 0x600000031b20>, --> weakObj - block
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] 对象内存地址:0x7fff5e5d9898, 对象本身:0x600000031b20, 指向对象:<Obj_A: 0x600000031b20>, --> strongObj - block
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] obj设置为nil
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] Obj A dealloc
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] 对象内存地址:0x7fff5e5d99b8, 对象本身:0x0, 指向对象:(null), --> obj
2017-08-16 15:52:19.973 MemoryLeak[21368:701529] 对象内存地址:0x7fff5e5d99b0, 对象本身:0x0, 指向对象:(null), --> weakObj
2017-08-16 15:52:19.973 MemoryLeak[21368:701529] 对象内存地址:0x600000240320, 对象本身:0x0, 指向对象:(null), --> weakObj - block
2017-08-16 15:52:19.973 MemoryLeak[21368:701529] 对象内存地址:0x7fff5e5d9898, 对象本身:0x0, 指向对象:(null), --> strongObj - block
2017-08-16 15:52:19.973 MemoryLeak[21368:701529] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

总结:

验证方法五 :

- (void)objProblem5 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __weak Obj_A *weakObj = obj;
    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"start---");
        __strong Obj_A *strongObj = weakObj;
        TLog(@"weakObj - block", weakObj);
        TLog(@"strongObj - block", strongObj);
        sleep(5);
        TLog(@"weakObj - block", weakObj);
        TLog(@"strongObj - block", strongObj);
        NSLog(@"end----");
    });
    sleep(1);
    NSLog(@"*************");
    NSLog(@"After 1s obj设置为nil");
    obj = nil;
    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);
    NSLog(@"*************");

    sleep(10);
    NSLog(@"After 10s");
    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印结果

2017-08-16 15:55:48.772 MemoryLeak[21408:703939] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:55:48.772 MemoryLeak[21408:703939] 对象内存地址:0x7fff5bed69b8, 对象本身:0x610000023c00, 指向对象:<Obj_A: 0x610000023c00>, --> obj
2017-08-16 15:55:48.772 MemoryLeak[21408:703939] 对象内存地址:0x7fff5bed69b0, 对象本身:0x610000023c00, 指向对象:<Obj_A: 0x610000023c00>, --> weakObj
2017-08-16 15:55:48.772 MemoryLeak[21408:704010] start---
2017-08-16 15:55:48.772 MemoryLeak[21408:704010] 对象内存地址:0x6000000535e0, 对象本身:0x610000023c00, 指向对象:<Obj_A: 0x610000023c00>, --> weakObj - block
2017-08-16 15:55:48.772 MemoryLeak[21408:704010] 对象内存地址:0x700002cc6d88, 对象本身:0x610000023c00, 指向对象:<Obj_A: 0x610000023c00>, --> strongObj - block
2017-08-16 15:55:49.772 MemoryLeak[21408:703939] *************
2017-08-16 15:55:49.772 MemoryLeak[21408:703939] After 1s obj设置为nil
2017-08-16 15:55:49.773 MemoryLeak[21408:703939] 对象内存地址:0x7fff5bed69b8, 对象本身:0x0, 指向对象:(null), --> obj
2017-08-16 15:55:49.773 MemoryLeak[21408:703939] 对象内存地址:0x7fff5bed69b0, 对象本身:0x610000023c00, 指向对象:<Obj_A: 0x610000023c00>, --> weakObj
2017-08-16 15:55:49.774 MemoryLeak[21408:703939] *************
2017-08-16 15:55:53.777 MemoryLeak[21408:704010] 对象内存地址:0x6000000535e0, 对象本身:0x610000023c00, 指向对象:<Obj_A: 0x610000023c00>, --> weakObj - block
2017-08-16 15:55:53.778 MemoryLeak[21408:704010] 对象内存地址:0x700002cc6d88, 对象本身:0x610000023c00, 指向对象:<Obj_A: 0x610000023c00>, --> strongObj - block
2017-08-16 15:55:53.778 MemoryLeak[21408:704010] end----
2017-08-16 15:55:53.778 MemoryLeak[21408:704010] Obj A dealloc
2017-08-16 15:55:59.774 MemoryLeak[21408:703939] After 10s
2017-08-16 15:55:59.775 MemoryLeak[21408:703939] 对象内存地址:0x7fff5bed69b8, 对象本身:0x0, 指向对象:(null), --> obj
2017-08-16 15:55:59.775 MemoryLeak[21408:703939] 对象内存地址:0x7fff5bed69b0, 对象本身:0x0, 指向对象:(null), --> weakObj
2017-08-16 15:55:59.775 MemoryLeak[21408:703939] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

总结 :


对象之间强引用

__block的理解

验证方法一:

- (void)blockProblem1 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __block Obj_A *blockObj = obj;

    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);

    NSLog(@"obj设置为nil");
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    
    void(^testBlock)() = ^(){
        NSLog(@"***********开始block***********");
        TLog(@"blockObj - block",blockObj);
        Obj_A *obj2 = [[Obj_A alloc]init];
        TLog(@"obj2",obj2);
        NSLog(@"将blockObj = obj2,只要blockObj不再应用obj,那么obj则释放");
        blockObj = obj2;
        TLog(@"blockObj - block",blockObj);
        NSLog(@"***********结束block***********");
    };
    
    NSLog(@"设置block内容之后");
    
    TLog(@"blockObj\n--------------------",blockObj);
    
    NSLog(@"运行block");
    testBlock();
    TLog(@"blockObj\n--------------------",blockObj);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印结果

2017-08-16 16:04:58.457 MemoryLeak[21496:708962] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] 对象内存地址:0x7fff555dc9b8, 对象本身:0x600000022c20, 指向对象:<Obj_A: 0x600000022c20>, --> obj
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] 对象内存地址:0x7fff555dc9b0, 对象本身:0x600000022c20, 指向对象:<Obj_A: 0x600000022c20>, --> blockObj
----------
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] obj设置为nil
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] 对象内存地址:0x7fff555dc9b8, 对象本身:0x0, 指向对象:(null), --> obj
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] 对象内存地址:0x7fff555dc9b0, 对象本身:0x600000022c20, 指向对象:<Obj_A: 0x600000022c20>, --> blockObj
----------
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 设置block内容之后
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 对象内存地址:0x61000004a408, 对象本身:0x600000022c20, 指向对象:<Obj_A: 0x600000022c20>, --> blockObj
--------------------
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 运行block
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] ***********开始block***********
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 对象内存地址:0x61000004a408, 对象本身:0x600000022c20, 指向对象:<Obj_A: 0x600000022c20>, --> blockObj - block
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 对象内存地址:0x7fff555dc8e8, 对象本身:0x608000022a00, 指向对象:<Obj_A: 0x608000022a00>, --> obj2
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 将blockObj = obj2,只要blockObj不再应用obj,那么obj则释放
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] Obj A dealloc
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] 对象内存地址:0x61000004a408, 对象本身:0x608000022a00, 指向对象:<Obj_A: 0x608000022a00>, --> blockObj - block
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] ***********结束block***********
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] 对象内存地址:0x61000004a408, 对象本身:0x608000022a00, 指向对象:<Obj_A: 0x608000022a00>, --> blockObj
--------------------
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] Obj A dealloc

总结 :

验证方法二 :

- (void)blockProblem2 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __block Obj_A *blockObj = obj;

    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);

    
    NSLog(@"obj设置为nil");
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    NSLog(@"设置block内容");
    
    void(^testBlock)() = ^(){
        TLog(@"blockObj - block",blockObj);
    };
    
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    
    NSLog(@"运行block");
    testBlock();
    TLog(@"blockObj",blockObj);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印结果


总结

验证方法三 :

- (void)blockProblem3 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");

    Obj_A *obj = [[Obj_A alloc]init];
    __block Obj_A *blockObj = obj;

    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);

    NSLog(@"obj设置为nil");
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    NSLog(@"设置block内容");
    
    void(^testBlock)() = ^(){
        TLog(@"blockObj - block",blockObj);
        NSLog(@"blockObj设置为nil");
        blockObj = nil;
    };
    NSLog(@"obj设置为nil");
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    NSLog(@"运行block");
    testBlock();
    TLog(@"blockObj",blockObj);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印结果

2017-08-16 16:09:30.042 MemoryLeak[21537:711747] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] 对象内存地址:0x7fff5e9709b8, 对象本身:0x600000039560, 指向对象:<Obj_A: 0x600000039560>, --> obj
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] 对象内存地址:0x7fff5e9709b0, 对象本身:0x600000039560, 指向对象:<Obj_A: 0x600000039560>, --> blockObj
----------
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] obj设置为nil
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] 对象内存地址:0x7fff5e9709b8, 对象本身:0x0, 指向对象:(null), --> obj
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] 对象内存地址:0x7fff5e9709b0, 对象本身:0x600000039560, 指向对象:<Obj_A: 0x600000039560>, --> blockObj
----------
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 设置block内容
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] obj设置为nil
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 对象内存地址:0x7fff5e9709b8, 对象本身:0x0, 指向对象:(null), --> obj
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 对象内存地址:0x608000050ee8, 对象本身:0x600000039560, 指向对象:<Obj_A: 0x600000039560>, --> blockObj
----------
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 运行block
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 对象内存地址:0x608000050ee8, 对象本身:0x600000039560, 指向对象:<Obj_A: 0x600000039560>, --> blockObj - block
2017-08-16 16:09:30.044 MemoryLeak[21537:711747] blockObj设置为nil
2017-08-16 16:09:30.044 MemoryLeak[21537:711747] Obj A dealloc
2017-08-16 16:09:30.044 MemoryLeak[21537:711747] 对象内存地址:0x608000050ee8, 对象本身:0x0, 指向对象:(null), --> blockObj
2017-08-16 16:09:30.044 MemoryLeak[21537:711747] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

总结


关于__weak和__strong的总结

总结


参考博文 :
block教程系列
__weak与__block区别

上一篇 下一篇

猜你喜欢

热点阅读