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

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

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

    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确实可以避免这个问题, 但我还是很好奇, 到底是什么原因造成了内存的暴增?


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


试着讲清楚你的疑问。

先看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];
    }
}

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

【热门文章】
【热门文章】