iOS 是什么造成了运行占用内存的暴增?

 pfm4191006 发布于 2022-10-28 07:15

首先看一段很简单的代码:

    NSString *urlStr = @"http://120.25.226.186:32812/resources/videos/minion_10.mp4";
    NSURL *url = [NSURL URLWithString:urlStr];
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[url] = @"ZYCoderr";
    while (1) {
        NSString *value = dict[url];
    }

运行后点击Xcode的Debug Session来看模拟器的状态:

CPU占用为99%。但我想问的问题不是关于CPU的, 而是关于内存的。接下来我稍微改变一下上面的代码:

NSString *urlStr = @"http://120.25.226.186:32812/resources/videos/minion_10.mp4";
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[url.absoluteString] = @"ZYCoderr";
while (1) {
    NSString *value = dict[url.absoluteString];
}

我仅仅是改变了字典的key。再运行一遍:

这是程序运行10s后的样子。我第一次注意到这个问题的时候内存已经飙到了9.9G, 鼠标几乎都快移不动了(麻麻, 编程好可怕……)

经过我多次尝试, 发现问题只出在第6行这一行身上面。当你将url.absoluteString作为你用来取值的key使用的时候, 就会发生内存暴增的问题。 就算你采取下面的写法:

    NSString *key = url.absoluteString;
    NSString *value = dict[key];

情况仍然不可避免。但如果你直接采用下面的写法:

    NSString *value = dict[urlStr];

你会发现问题又消失了。
另外, 你可能会在while循环中打一个log,然后发现内存暴增的情况又“消失”了。但事实上并不是这样, 这只是while循环运行速度减慢了而已, 内存仍在稳步增长。

虽然不使用url.absoluteString当做字典的key确实可以避免这个问题, 但我还是很好奇, 到底是什么原因造成了内存的暴增?

2 个回答
  • url.absoluteString会持续的创建新的实例,系统释放内存跟不上,打印Log的时候,系统会有一点时间去释放内存,所有内存增加稍微减缓,但是还是持续增长

    2022-10-29 10:39 回答
  • 试着讲清楚你的疑问。

    先看absoluteString的属性声明(XCode7.3.1版本),readonly && copy,看到两个属性,应该有一种直觉,这个值是一个计算值(可参考Swift的属性声明)。

    @property (readonly, copy) NSString *absoluteString;

    再看文档

    Discussion
    This property’s value is calculated by resolving the receiver’s string against its base according to the algorithm given in RFC 1808.

    可以确定,absoluteString是一个计算值。如果你看过《Effective Objective-C 2.0》,那么可以再进一步,这个值是autorelease的。

    autorelease的值在循环中会大量消耗内存,一般会使用autoreleasepool来降低内存峰值。

    可以看下面两个测试例子

    低内存版:

    while (1) {
        NSString *a = [[NSString alloc] initWithFormat:@"asdfasdfasfasdf"];
    }

    高内存版:

    while (1) {
        NSString *a = [NSString stringWithFormat:@"asdfasdfasfasdf"];
    }

    针对你的问题,稍加改动

    while (1) {
        @autoreleasepool {
            NSString *value = dict[url.absoluteString];
        }
    }

    可以看到,内存已经不会暴涨了。

    2022-10-29 10:43 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有