AVCam内存不足警告

发布于 2024-12-10 19:47:53 字数 253 浏览 3 评论 0原文

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

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

This is less a question and more a record of what I've found around the AVCam sample code provided by Apple for iOS4 and 5 camera manipulation. The symptoms of the problem for me were that my app would crash on launching the AVCamViewController after taking around 5-10 photos.

I ran the app through the memory leak profiler and there were no apparent leaks but on inspection with the Activity Monitor I discovered that something called mediaserverd was increasing by 17Mb every time the camera was launched and when it reached ~100Mb the app crashed with multiple low memory warnings.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

献世佛 2024-12-17 19:47:53

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

接下来,我逐步完成了捕获管理器的创建过程,发现在调用 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 方法中取出相同的行。

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

现在使用活动监视器进行测试,mediaserverd 进程仅占用 5-17Mb,并且崩溃停止了!

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

First thing I did was put logging into the dealloc methods of all the AVCam files. I quickly discovered that the AVCamCaptureManager and AVCamRecorder weren't being deallocated when the AVCamViewController was. I checked out the retain and release calls and they appeared to balance so I put a breakpoint on the [captureManager release] and discovered that it had a retainCount of 2 AFTER the release (and hence the AVCamCaptureManager dealloc wasn't being called).

Next I stepped through the creation process for the capture manager and discovered that it had a retain count of 3 immediately after the init method was called.

Stepping through the init method and checking the retain count on every line I discovered the following two lines were both incrementing the retain count:

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

Looking through I found that the removeObserver counterparts were INSIDE the dealloc method of the AVCamCaptureManager (which wasn't being called) and so the retain count never dropped to 0.

To fix it I created a new public removeObservers method:

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

and taking the same lines OUT of the AVCamCaptureManager dealloc method.

Calling [captureManager removeObservers]; and THEN calling [captureManager release]; in the AVCamViewController dealloc method successfully drops the retain count to 0.

Testing with the Activity Monitor now has the mediaserverd process humming at only 5-17Mb and the crashing stops!

Hope this helps anyone else having this problem!

dawn曙光 2024-12-17 19:47:53

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

这是修订说明

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


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

__weak AVCamCaptureManager *weakSelf = self;

事实上,__block 的语义随着 ARC 的改变而改变。在 MRC 中,它会导致变量被弱引用,而在 ARC 中则不会,因此必须使用 __weak 来实现此目的。

有关此主题的更多信息可以在此处找到:在实现 API 时,如何避免在块中捕获 self?

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


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

功能:

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

Apple revised the sample code on Oct 17 2013, fixing the retain cycle. The issue is due to a improper usage of self within the blocks defined in the init.

Here's the revision description

Fixed retain cycles in AVCaptureManager that result in leaks. NOTE - if you've adapted AVCam code in your app, you should adopt the fixes made here in AVCaptureManager.m's init method. Without these fixes, you may be leaking AVCaptureManager instances and leaving the camera running constantly while your app is in the foreground.


However, the fix they introduced only works in case of Manual Retain Count. If you are using ARC on the project, apart from getting rid of release/retain calls and other obvious things, the storage qualifier for weakSelf has to be changed from __block to __weak, like follows.

__weak AVCamCaptureManager *weakSelf = self;

In fact the semantic of __block changed with ARC. In MRC it caused the variable to be weakly referenced, wheres in ARC it does not and __weak must be used for this purpose.

More information about this topic can be found here: How do I avoid capturing self in blocks when implementing an API?

Using the new init implementation from the last revision and using __weak instead of __block, finally caused the dealloc method to be properly called.


Finally, for those who hate to carry around old legacy code, here's a modernized version of the AVCam project: https://github.com/Gabro/AVCam

Features:

  • memory leaks free
  • uses ARC
  • modern Objective-C syntax
  • minor UI fixes for iOS 7
笑红尘 2024-12-17 19:47:53

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

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

希望这对其他人有帮助。

REF: 使用 NSNotificationCenter 时未调用视图控制器 dealloc带有ARC的代码块方法

Ran into this problem recently. I found that the real root problem was that deviceConnectedBlock and deviceDisconnectedBlock were implicitly referring to self, leading to retain cycles. To fix it, change all the ivar references in those blocks to use weakSelf.

This way, you won't need to remember to call a teardown method explicitly.

Hope this helps someone else.

REF: View controller dealloc not called when using NSNotificationCenter code block method with ARC

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文