【问题标题】:AVCam memory low warningAVCam 内存不足警告
【发布时间】:2011-12-09 02:41:58
【问题描述】:

这不是一个问题,而是我在 Apple 为 iOS4 和 5 相机操作提供的 AVCam 示例代码中发现的内容的记录。对我来说,问题的症状是我的应用在拍摄了大约 5-10 张照片后在启动 AVCamViewController 时会崩溃。

我通过内存泄漏分析器运行应用程序,没有明显的泄漏,但在使用 Activity Monitor 进行检查时,我发现每次启动相机时,名为 mediaserverd 的东西都会增加 17Mb,当它达到 ~100Mb 时,应用程序崩溃了有多个内存不足警告。

【问题讨论】:

标签: xcode didreceivememorywarning avcam


【解决方案1】:

我做的第一件事是将日志记录到所有 AVCam 文件的 dealloc 方法中。我很快发现 AVCamCaptureManager 和 AVCamRecorder 没有在 AVCamViewController 被释放时被释放。我检查了保留和释放调用,它们似乎是平衡的,所以我在 [captureManager 释放] 上放置了一个断点,发现它在释放后的 retainCount 为 2(因此没有调用 AVCamCaptureManager 释放)。

接下来,我逐步完成了捕获管理器的创建过程,发现在调用 init 方法后立即保留计数为 3。

逐步执行 init 方法并检查每一行的保留计数,我发现以下两行都在增加保留计数:

[self setDeviceConnectedObserver=[notificationCenter addObserverForName:AVCaptureDeviceWasConnectedNotification object:nil queue:nil usingBlock:deviceConnectedBlock]];
[self setDeviceDisconnectedObserver=[notificationCenter addObserverForName:AVCaptureDeviceWasDisconnectedNotification object:nil queue:nil usingBlock:deviceDisconnectedBlock]];

通过查看,我发现 removeObserver 对应项位于 AVCamCaptureManager 的 dealloc 方法中(未被调用),因此保留计数从未降至 0。

为了修复它,我创建了一个新的公共 removeObservers 方法:

 -(void)removeObservers {
     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
     [notificationCenter removeObserver:[self deviceConnectedObserver]];
     [notificationCenter removeObserver:[self deviceConnectedObserver]];
 }

并从 AVCamCaptureManager dealloc 方法中取出相同的行。

调用 [captureManager removeObservers];然后调用 [captureManager release];在 AVCamViewController dealloc 方法中成功将保留计数降至 0。

使用 Activity Monitor 进行测试后,现在 mediaserverd 进程的嗡嗡声只有 5-17Mb,并且崩溃停止了!

希望这可以帮助其他遇到此问题的人!

【讨论】:

  • 更好...强大的 SO 神允许我现在回答我自己的问题 ;)
  • 强大的 SO 神允许我通过 +1 表示感谢;)
  • 很好的描述。我相信我们遇到了同样的问题。
  • 非常感谢!我们遇到了同样的问题。
  • 太棒了,如果我能在网上给你买啤酒我会的!
【解决方案2】:

Apple 于 2013 年 10 月 17 日修订了示例代码,修复了保留周期。该问题是由于在init 中定义的块中未正确使用self

这是修订说明

修复了 AVCaptureManager 中导致泄漏的保留周期。 注意 - 如果你在你的应用中修改了AVCam 代码,你应该采用AVCaptureManager.minit 方法中的修复。如果不进行这些修复,您可能会泄漏AVCaptureManager 实例并让相机在您的应用处于前台时持续运行。


但是,他们引入的修复仅适用于手动保留计数。如果您在项目中使用 ARC,除了摆脱 release/retain 调用和其他明显的东西之外,weakSelf 的存储限定符必须从 __block 更改为 __weak,如下所示。

__weak AVCamCaptureManager *weakSelf = self;

事实上,__block 的语义随着 ARC 的改变而改变。在 MRC 中,它导致变量被弱引用,而在 ARC 中则没有,__weak 必须用于此目的。

可以在此处找到有关此主题的更多信息:How do I avoid capturing self in blocks when implementing an API?

使用最新版本中的新init实现并使用__weak而不是__block,最终导致dealloc方法被正确调用。


最后,对于那些讨厌携带旧代码的人,这里是 AVCam 项目的现代化版本:https://github.com/Gabro/AVCam

特点:

  • 内存泄漏免费
  • 使用 ARC
  • 现代 Objective-C 语法
  • 针对 iOS 7 的小部分 UI 修复

【讨论】:

  • 嗨 Gabriele,我看过你的 AVCam 项目。您可以将“ARC 兼容”注释更改为“ARC 独有”吗?我已将它添加到我的非 ARC 项目中,并且存在一些与使用 ARC 专有功能有关的编译失败。
  • @RedNightingale 绝对是,用词确实很糟糕。顺便说一句,如果您愿意,即使在非 ARC 项目中,您也可以有选择地在特定文件上启用 ARC。希望对您有所帮助。
  • 我会调查的。已经尝试了 Apple 代码的新修订版,它们似乎终于可以正常工作了,所以我会宣传这个作为答案。
  • 如果可以,请使用 Gabriele 的 AVCam 代码。如果您在现有项目中编辑早期版本的 AVCam,请务必修改您的 init 方法以在需要的任何地方使用weakSelf。如果您仍然遇到问题,请在 init 方法的末尾开始检查 self 的 retainCounts。如果您看到没有意义的 retainCounts,那么您错过了将某些内容转换为使用 weakSelf。
  • 在 iOS 9 上运行 Apple 演示肯定仍然存在内存泄漏,这些更新仍然可以修复它
【解决方案3】:

最近遇到了这个问题。我发现真正的根本问题是 deviceConnectedBlock 和 deviceDisconnectedBlock 隐含地引用了自我,导致保留循环。要修复它,请将这些块中的所有 ivar 引用更改为使用 weakSelf。

这样,您无需记住显式调用拆卸方法。

希望这对其他人有所帮助。

参考号:View controller dealloc not called when using NSNotificationCenter code block method with ARC

【讨论】:

  • 我确实在块中有一个对 self 的引用。我将其替换为 weakSelf 并恢复为“正常”的 AVCAM 发布代码。 CaptureManager 仍然没有调用 dealloc。您链接到的文章引用了 __weak 以供参考,但这仅适用于 ARC 代码(我目前没有使用)。我需要使用 __block 代替,但对“块”了解不够,无法提出一个等效的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-02
相关资源
最近更新 更多