【问题标题】:SDWebImage - Memory leak in UITableView?SDWebImage - UITableView 中的内存泄漏?
【发布时间】:2013-11-06 08:31:49
【问题描述】:

我很抱歉,因为这可能是一个愚蠢和菜鸟的问题......

我在 cellForRowAtIndexPath 方法中使用 SDWebImageUITableView 中显示图片,使用经典

[cell.pointPicture setImageWithURL:[NSURL URLWithString:thePoint.imageURL] placeholderImage:[UIImage imageNamed:POINT_DEFAULT_IMAGE]];

(显示的图片是轻巧且压缩良好的 jpg,只是一些 ko,是的,我当然使用的是 dequeueReusableCellWithIdentifier)。

当我使用“Instrument - Allocations”检查我的应用程序并向下滚动我的 UITableView(有 40 个包含图片的单元格,有点像 Instagram)时,我使用了大量内存! (见截图)

但它似乎是“VM”,尤其是 coreGraphics 库中的“VM: CG raster data”。

所以问题是:

  • 正常吗?
  • 这是一个严重的问题吗?
  • 有没有办法避免这种情况?

很抱歉,在网上搜索了几下后,我找不到任何有关“VM:CG 栅格数据”的相关信息......知道吗?提前致谢!

【问题讨论】:

  • 这是渲染服务器用于实际显示在屏幕上的视图的所有光栅化版本。您可能会遇到较大的内存负载,尤其是当您在视图中有要缩小的大图像时。运行泄漏仪器,看看是否有任何实际泄漏。
  • 感谢@JasonCoco 的这些解释。是的,图片大小比显示它的视图大。对于泄漏,仪器未显示任何...
  • @JasonCoco 我只是尝试显示视图的确切尺寸(640x640,然后是 320x320)以避免所有缩小。不幸的是,使用的 CG 恢复数据量保持不变......还有一点奇怪的是,使用的内存量从未释放......我也找不到任何内存泄漏。

标签: ios uitableview memory-management memory-leaks sdwebimage


【解决方案1】:

虽然NSCache 会在内存不足的系统通知中释放内存,但在程序的其他部分中,更关键的对象(并且内存占用更小)也会被丢弃。

最好将库的maxMemoryCost(设置NSCachetotalCostLimit)设置为一个限制,以防止SDWebImage触发内存通知。

【讨论】:

    【解决方案2】:

    正如从事 SDWebImage 工作的人向我解释的那样:

    SDWebImage 缓存图像正在使用NSCache。它是可丢弃的内存。请参阅Apple documentation,因此这是完全正常的行为,如果需要,内存会被释放。

    【讨论】:

    • 虽然确实会在需要时释放内存,但您可以通过做两件事来获得更好的性能 1)在下载时调整图像大小以满足您的需求 2)修改 SDWebImage 中的缓存逻辑以将调整大小的图像存储在缓存中。我这样做了,我的内存占用现在从 200MB 降到了大约 40MB。我在一个网格中有一个 uicollectionview,有 2000 张图片 - 所有图片都是从服务器下载的。
    • @AnilPuttabuddhi 你可以在那里发布你的代码以显示更多细节吗?
    【解决方案3】:

    我有同样的问题。我的问题似乎源于 SDWebImage 缓存以外的其他东西,但由于它确实有助于内存积累,所以我首先想到的是缓存可能是我的问题的原因。但事实并非如此。可能是你有同样的问题。请记住,我使用的是 ARC。

    • 使用Leaks 模板运行分析器并检查Allocation Summary 中您自己的类的分配。
    • 深入研究它们并检查它们是如何分配的,如果有泄漏。请注意,Leaks 仪器中不会出现泄漏,因为您使用的是 ARC。因此 Instruments 可以认为一切正常,但仍有可能在某处泄漏。通过深入了解您自己的班级分配情况,您可以找出问题所在。
    • 请记住,保留/释放计数信息仅在使用 Leaks 模板时提供,而不是在使用 Allocations 模板时提供。

    我的问题是我直接从块中引用实例变量和 self 而没有将它们重新分配给 __weak 变量。当 self 在块中使用时,它会自动被 ARC 保留,有时永远不会释放。弱引用可以防止这种情况发生。

    例如,这是错误

    [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
        [self.view setContentOffset:CGPointMake(0.0, kKeyboardOffset) animated:YES];
    }];
    

    您应该像这样使用__weak 引用来调用self:

    __weak YourViewControllerClass *weakSelf = self;
    [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
        [weakSelf.view setContentOffset:CGPointMake(0.0, kKeyboardOffset) animated:YES];
    }];
    

    由于我的应用程序使用了很多块,因此Leaks 仪器无法检测到大量泄漏。当我修复它们时,内存问题就消失了。

    我希望这会有所帮助。

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题并找到了根本原因,至少在我的实施中。

      根本原因

      根本原因是我的表格单元格存储了一个 strong 指针,该指针指向存储在 SDWebImage 缓存中的图像。这个strong指针,导致SDWebImageremoveAllObjects的内存释放函数在收到来自iOS的内存警告时没有释放任何内存。

      解决方案 1 - 在 ViewController 中保留 weak 指针,并仅允许 SDWebImage 保留指向所有 UIImage 对象的强指针。

      解决方案 2 - 实现 - (void)prepareForReuse 并将图像指针设置为 nil

      要测试此解决方案,请运行您的应用程序并模拟内存警告 - 您将能够看到已删除的数据

      【讨论】:

      • 能否提供解决方案2的代码sn-p?
      • 根据 Apple 和我的测试,prepareForReuse 在被重用之前被调用,因此在指针设置为新图像之前,因此在此之前将其设置为 nil 不会产生区别。如果可以在单元格入队时将它们设置为nil,但似乎没有办法。
      • @avihaya 嗨,兄弟。你能通过在上面播放更多代码来编辑答案吗?
      猜你喜欢
      • 2013-12-24
      • 1970-01-01
      • 2012-07-09
      • 2011-06-03
      • 2012-04-03
      • 1970-01-01
      • 2011-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多