【问题标题】:'NSData dataWithContentsOfURL:' memory leak iOS 9.x?'NSData dataWithContentsOfURL:' iOS 9.x 内存泄漏?
【发布时间】:2015-12-28 12:10:16
【问题描述】:

我的代码如下:

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSString *theURLString = @"http://website.com/musicFile";
    NSData *theData = [NSData dataWithContentsOfURL:[NSURL URLWithString:theURLString]];
}

没有什么特别的。我什至没有使用后台线程。

这是我在 iOS 8.x 上得到的行为(以及我期望得到的行为):

这样,NSData 被完全释放,所有占用的内存都回来了。

然而,iOS 9.x 让我大吃一惊:

我的问题是:

  1. 在 iOS 9.x 中,大约 100 MB 的空间被白白浪费掉了。我怎样才能让他们回来?有什么解决方法吗?

  2. iOS 8.x 最大占用 136.2 MB,而 iOS 9.x 最大占用 225.9 MB。为什么会这样?

  3. iOS 9.x 中发生了什么?

更新 #1:

我也尝试过使用 NSURLSession 'dataTaskWithURL:completionHandler:' (感谢@CouchDeveloper)。这减少了泄漏,但并不能完全解决问题(这次是 iOS 8.x 和 iOS 9.x)。

我使用了下面的代码:

NSURLSession *theURLSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionDataTask *theURLSessionDataTask = [theURLSession dataTaskWithURL:[NSURL URLWithString:theURLString]
                                                               completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error)
                                                   {
                                                       NSLog(@"done");
                                                   }];
[theURLSessionDataTask resume];

如您所见,仍有 30 MB 丢失。

更新 #2:

上述测试是使用 Xcode 模拟器完成的。

不过,我也决定在实际的 iOS 9.2 iPhone 4S 上进行测试(由 @Sohil R. Memon 推荐)。

'NSData dataWithContentsOfURL:'的结果如下:

使用'NSURLSession dataTaskWithURL:completionHandler:'的结果如下:

看起来 'NSData dataWithContentsOfURL:' 在实际设备上可以完美运行,而 'NSURLSession dataTaskWithURL:completionHandler:' -- 不能。

但是,有谁知道在实际设备和 Xcode 模拟器上显示相同信息的解决方案?

【问题讨论】:

  • 请尝试在实际设备上测试并将屏幕截图粘贴到此处!
  • 请多次尝试下载以查看是否堆叠。如果它是恒定的,那么这个“泄漏”可能是一个网络缓冲区——它被缓存了,因此不是泄漏。
  • @CouchDeveloper 上述所有方法均已测试 5-10 次。

标签: ios objective-c xcode memory nsdata


【解决方案1】:

在 iOS 9.x 中,大约 100 MB 的空间被白白浪费了。我怎样才能让他们回来?有什么解决方法吗?

出于几个原因,我们应该使用NSURLSession 从网络服务下载数据。因此,这不是一种解决方法,而是正确的方法。

iOS 9.x 中发生了什么?

我不知道 - 可能是缓存数据、网络缓冲区或其他一些问题。但这无关紧要 - 您应该尝试使用 NSURLSession 的正确方法。

来自docs

重要

不要使用这种同步方法来请求基于网络的 URL。对于基于网络的 URL,此方法会在慢速网络上阻塞当前线程数十秒,导致用户体验不佳,并且在 iOS 中可能会导致您的应用被终止。

相反,对于非文件 URL,请考虑使用 NSURLSession 类的 dataTaskWithURL:completionHandler: 方法。详情请见URL Session Programming Guide

编辑:

这些“原因”是:

  • NSURLSession 专门用于加载远程资源。

  • NSURLSession 方法是异步的,这对于仅在可感知的持续时间后完成的方法至关重要(它不会阻塞调用线程)。

  • 会话可以通过默认方法或自定义委托来处理身份验证。

  • 可以取消会话任务。

【讨论】:

  • 1) 您能否解释一下“始终使用 NSURLSession 的两个原因”? (请将其添加到您的答案中)
  • 2) NSURLSession 很强大,但它不是一个快速的单行代码解决方案。但是,一旦我对 NSURLSession 进行了一次硬试,我就会将答案标记为“正确”。
  • 'dataTaskWithURL:completionHandler:' 导致大约 40 MB 的内存未被释放(iOS 8.x 和 iOS 9.x 现在都是)。
  • @OlDor 阐明了使用NSURLSession 获取远程资源的原因。
【解决方案2】:

Here 也是一个帮助我的答案。答案是改用[NSData dataWithContentsOfURL:url options:0 error:&error];

希望对你有帮助

【讨论】:

  • 您正在下载的文件的实际大小是多少?
猜你喜欢
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 2018-01-14
  • 2011-12-28
  • 2012-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多