美文网首页
IOS 内存分析 Xcode

IOS 内存分析 Xcode

作者: 越天高 | 来源:发表于2020-06-02 13:31 被阅读0次

    主要目的就是为了检测程序是否存在内存泄露

    • MRC target -> build setting -> 搜索 automatic reference counting
      截屏2020-06-01下午4.32.53.png

    1. 静态内存分析(Analyze)

    • 概念:

    静态内存分析是不运行程序,直接对代码进行分析.
    根据代码的上下文的语法结构,来分析内存状况

    • 作用:
      调整环境到MRC

    逻辑错误:访问未初始化的变量或者野指针等;
    声明错误:从未使用过的对象;
    内存管理错误:如内存泄漏等;(MRC&ARC)

    • 缺点:

    不一定准确,但是如果发现有提示,那么去结合上下文看一下,这里的代码是否有问题

    • 场景演练(OC):

      MRC 下桥接
      Foundation 到 CoreFoundation框架的数据类型转换
      强制数据类型转换, 不会移交对象内存管理所有权
      CoreFoundation 到 Foundation框架的数据类型转换
      强制数据类型转换, 不会移交对象内存管理所有权


    MRC下的静态分析

     //    > 逻辑错误:访问未初始化的变量或
            NSObject *obj;
            NSLog(@"%@", obj);
    
    未初始化
     // 野指针等;
        NSObject *obj = [[NSObject alloc] init];
        [obj release];
        NSLog(@"%@",obj);
    
    野指针
    // > 声明错误:从未使用过的对象;
         NSObject *obj = [[[NSObject alloc] init] autorelease];
    
    从未使用过
     // 测试不准确的地方
        NSObject *obj = [self lost];
        NSLog(@"%@", obj);
        [obj release];
        
    }
    
    - (NSObject *)lost
    {
        return [[NSObject alloc]init];
    }
    
    不准确

    使用Corefoundation的框架内容要记得释放


    mrc使用corefoundation

    MRC下的桥接

    - (void)mrc
    {
        //MRC下桥接
        //Foundation 到 CoreFoundation框架的数据类型转换
        NSString *str = [[NSString alloc] init];
         // CFStringRef , 这种转换, 属于直接转换, 不会移交对象的内存管理权
        CFStringRef strRef = (CFStringRef)str;
        NSLog(@"%@", strRef);
        [str release];
        
        //CoreFoundation 往 Foundation框架的数据类型转换
         CFStringRef strRef2 = CFStringCreateWithCString(CFAllocatorGetDefault(), "123", kCFStringEncodingUTF8);
         // 这种转换, 属于直接转换, 不会移交对象的内存管理权
        NSString *str2 = (NSString *)strRef2;
        CFRelease(strRef2);
        
    }
    

    ARC下的桥接

     //Foundation 到 CoreFoundation框架的数据类型转换
        NSString *str = [[NSString alloc] init];
         // (__bridge CFStringRef)  等同于 MRC下面的直接转换, 不会移交对象的内存管理权
        CFStringRef strRef = (__bridge CFStringRef)(str);
        
        NSLog(@"%@", strRef);
        
        // CFBridgingRetain == __bridge_retained CFStringRef
           // 这种方式转换, 会移交对象的内存管理权
        CFStringRef strRef2 = (__bridge_retained CFStringRef)(str);
        NSLog(@"%@", strRef2);
        CFRelease(strRef2);
        
        //CoreFoundation 到 Foundation框架的数据类型转换
        CFStringRef strRef3 = CFStringCreateWithCString(CFAllocatorGetDefault(), "123", kCFStringEncodingUTF8);
        // __bridge NSString * 等同于 MRC下面的直接转换, 不会移交对象的内存管理权, 还是释放原来的对象
    //    NSString *str3 = (__bridge NSString*)(strRef3);
    //    NSLog(@"%@", str3);
    //    CFRelease(strRef3);
        // CFBridgingRelease == __bridge_transfer NSString *
        // 这种方式转换, 会移交对象的内存管理权
        NSString *str4 = (__bridge_transfer NSString *)(strRef3);
        NSLog(@"%@", str4);
    

    关于Swift中使用CoreFoundation 数据类型

    使用了"类型重映射"机制, 转换成为了能够自动管理内存的对象, 不需要我们手动释放


    内存分配

    作用

    查看是内存的分配情况
    查看内存是否有释放

    • UIImage 的两种创建方法测试
    • 加载UIImage的不同方式
     override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
        {
             // 通过 named 创建的图片资源, 不会被释放, 在内存中, 只有一份
            //let imageNew = UIImage(named: "liudog.png")
            
            let  path = Bundle.main.path(forResource: "liudog.jpg", ofType: nil)
    //图片没有缓存,可以被释放,
            let imageNew = UIImage(contentsOfFile: path!)
            
            if imageView == nil
            {
                return
            }
            imageView.image = imageNew
            
        }
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?)
        {
            if imageView == nil
            {
                return
            }
            imageView.removeFromSuperview()
        }
    

    概念解释

    Anonymous VM(匿名虚拟内存)是系统为程序预留的、可能会立即被重复使用的一部分可用内存

    图片使用技巧

    图片在沙盒中的存在形式

    1.如果项目的Deployment Target <= 6.x (不支持图片压缩), 所有图片直接暴露在沙盒的资源包(main Bundle), 不会压缩到Assets.car文件

    1. 如果项目的Deployment Target >= 7.x (支持图片压缩)

    1 放在Images.xcassets里面的所有图片会压缩到Assets.car文件, 不会直接暴露在沙盒的资源包(main Bundle)
    2 没有放在Images.xcassets里面的所有图片会直接暴露在沙盒的资源包(main Bundle), 不会压缩到Assets.car文件

    1. 使用对比
    • 会压缩到Assets.car文件, 没有直接暴露在沙盒的资源包(main Bundle)
      条件 : "Deployment Target >= 7.x" 并且是 "放在Images.xcassets里面的所有图片"
      影响 : 无法得到图片的全路径, 只能通过图片名(imageNamed:方法)来加载图片, 永远会有缓存
    • 不会压缩到Assets.car文件, 直接暴露在沙盒的资源包(main Bundle)
      ** 条件 :** 除1> 以外的所有情况
      ** 影响 :** 可以得到图片的全路径, 可以通过全路径(imageWithContentsOfFile:方法)来加载图片, 不会有缓存
    1. 结论
    • 小图片\使用频率比较高的图片,放在Images.xcassets里面
    • 大图片\使用频率比较低的图片(一次性的图片, 比如版本新特性的图片)

    动态内存分析

    • 作用 :检测程序在运行过程中是否存在内存泄露
    • 演练:> 模拟循环引用, 测试内存泄露


      Leaks

    4. 内存使用总结

    如何让程序尽量减少内存泄漏

    • 1.非ARC
    • Foundation对象(OC对象) : 只要方法中包含了alloc\new\copy\mutableCopy\retain等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次release或者1次autorelease
    • CoreFoundation对象(C对象) : 只要函数中包含了create\new\copy\retain等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次CFRelease或者其他release函数
    • 2.ARC
    • 只自动管理OC对象, 不会自动管理C语言对象
    • CoreFoundation对象(C对象) : 只要函数中包含了create\new\copy\retain等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次CFRelease或者其他release函数
    • 如果是swift里面, 使用* CoreFoundation对象(C对象) , 不需要手动释放. 因为使用了"类型重映射"机制, 可以把对象转换成为自动管理内存的对象

    相关文章

      网友评论

          本文标题:IOS 内存分析 Xcode

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