这不是一个问题,而是我在 Apple 为 iOS4 和 5 相机操作提供的 AVCam 示例代码中发现的内容的记录。对我来说,问题的症状是我的应用在拍摄了大约 5-10 张照片后在启动 AVCamViewController 时会崩溃。
我通过内存泄漏分析器运行该应用程序,没有明显的泄漏,但在使用 Activity Monitor 检查时,我发现每次启动相机时,名为 mediaserverd 的东西都会增加 17Mb,当它达到 ~100Mb 时,应用程序会因多个低点而崩溃内存警告。
这不是一个问题,而是我在 Apple 为 iOS4 和 5 相机操作提供的 AVCam 示例代码中发现的内容的记录。对我来说,问题的症状是我的应用在拍摄了大约 5-10 张照片后在启动 AVCamViewController 时会崩溃。
我通过内存泄漏分析器运行该应用程序,没有明显的泄漏,但在使用 Activity Monitor 检查时,我发现每次启动相机时,名为 mediaserverd 的东西都会增加 17Mb,当它达到 ~100Mb 时,应用程序会因多个低点而崩溃内存警告。
我做的第一件事是将日志记录到所有 AVCam 文件的 dealloc 方法中。我很快发现 AVCamCaptureManager 和 AVCamRecorder 没有在 AVCamViewController 被释放时被释放。我检查了保留和释放调用,它们似乎平衡了,所以我在 [captureManager 释放] 上放置了一个断点,发现它在释放后具有 2 的 retainCount (因此没有调用 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,并且崩溃停止了!
希望这可以帮助其他遇到此问题的人!
Apple 于 2013 年 10 月 17 日修改了示例代码,修复了保留周期。该问题是由于self
在init
.
这是修订说明
修复
AVCaptureManager
了导致泄漏的保留周期。注意- 如果你AVCam
在你的应用程序中修改了代码,你应该采用在AVCaptureManager.m
'sinit
方法中所做的修复。如果没有这些修复,您可能会泄漏AVCaptureManager
实例并让相机在您的应用程序处于前台时持续运行。
但是,他们引入的修复仅适用于手动保留计数。如果您在项目中使用 ARC,除了摆脱release
/retain
调用和其他明显的东西之外,存储限定符 forweakSelf
必须从更改__block
为__weak
,如下所示。
__weak AVCamCaptureManager *weakSelf = self;
实际上__block
用ARC改变了语义。在 MRC 中,它导致变量被弱引用,而在 ARC 中,它没有并且__weak
必须用于此目的。
可以在此处找到有关此主题的更多信息:如何在实现 API 时避免在块中捕获自我?
使用上一个修订版中的新init
实现并使用__weak
而不是__block
,最终导致该dealloc
方法被正确调用。
最后,对于那些讨厌携带旧代码的人,这里是该AVCam
项目的现代化版本:https ://github.com/Gabro/AVCam
特征:
最近碰到这个问题。我发现真正的根本问题是 deviceConnectedBlock 和 deviceDisconnectedBlock 隐含地引用自我,导致保留循环。要修复它,请将这些块中的所有 ivar 引用更改为使用 weakSelf。
这样,您就不需要记住显式调用拆卸方法。
希望这对其他人有帮助。