Board logo

标题: AutoreleasePool从入门到放弃(2) [打印本页]

作者: look_w    时间: 2019-3-8 19:31     标题: AutoreleasePool从入门到放弃(2)

2. AutoreleasePool使用场景
2.1降低系统内存峰值

如果在循环中大量创建autoreleased对象,而这些autoreleased对象只会在AutoreleasePool执行Pop操作(通俗点就是出了@AutoreleasePool block作用域)时才会销毁,通常情况下默认每个线程都有其对应的AutoreleasePool,而其执行Pop操作是在每次Runloop迭代时。而这个过程中未及时释放的autoreleased对象就会造成大量的内存堆积从而对性能造成一定的影响。

        for (NSInteger count = 0; count < 66666666; count++) {
            
                NSMutableString *autoreleasePool = [NSMutableString stringWithFormat"autoreleasePool"];
                NSMutableString *memoryMagic = [NSMutableString stringWithFormat"memoryMagic"];
        }

这里着重说明下,内存堆积是因为autoreleased对象未及时释放造成的,那么什么样的初始化方式创建出来的属于autoreleased对象呢?在ARC时代,编译器会根据初始化方法的命名规则来自动为我们插入相关的内存管理语句。非alloc/new/copy/mutableCopy开头的类方法默认返回的是autoreleased对象。

我们可以通过在代码中引入AutoreleasePool调试函数来查看当前释放池中的autoreleased对象来验证上诉结论。

    #import "ViewController.h"
     
    extern _objc_autoreleasePoolPrint();
     
    @interface ViewController ()
     


[编译器优化.png-481e68-1528701766440-0)]

未经编译优化.png

童鞋们可能说打脸了吧?[NSArray array]初始化返回的变量明明没有加入到AutoreleasePool中,也就说明不是autoreleased对象。这里先暂且告诉你们这是编译器在ARC中自己根据函数后续执行列表进行的TLS(Thread Local Storage)优化,后续再为大家解读优化的目的与原理。这里我们看未经编译优化的截图即可。

        for (NSInteger count = 0; count < 66666666; count++) {
        
            NSMutableString *autoreleasePool = [[NSMutableString alloc] initWithString"autoreleasePool"];
            NSMutableString *memoryMagic = [[NSMutableString alloc] initWithString"memoryMagic"];
            //注意初始化方式,这里非autoreleased对象不会造成内存积压
        }

    可能大家或多或少看过几篇大牛关于AutoreleasePool分析的文章 Objective-C Autorelease Pool 的实现原理、黑幕背后的Autorelease等,这里我要着重说明下NSString类已经被苹果过度优化了,在内存分析时要特别注意。上述文章中的测试例子将会生成nstaggedpointerstring对象,这是一种利用指针内存地址存储数据的优化手段,生成的并非真正的对象。所以在分析内存管理上会存在不准确的问题。关于nstaggedpointerstring的可以看下这篇文章【译】采用Tagged Pointer的字符串



2.2延长对象生命周期
2.2.1函数返回对象时
2.2.2函数参数为地址时

通过变量地址变向的从函数返回对象时同样也需要遵循ARC下的内存管理原则

        NSFileManager *manage = [NSFileManager defaultManager];
        [manage removeItemAtPath:filePath errorNSError * _Nullable __autoreleasing * _Nullable)];

在我们常用的文件管理操作中,对于NSError异常的捕获其实也就是从函数中变向的返回了一个NSError对象。在上述参数中我们能看到对应NSError的二级指针用了__autoreleasing内存管理字段来显式的对该对象执行了一个入池操作来延长对象生命周期。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0