Предупреждение о низком уровне памяти AVCam - PullRequest
7 голосов
/ 17 октября 2011

Это не вопрос, а скорее запись того, что я нашел вокруг примера кода AVCam, предоставленного Apple для iOS4 и манипуляции с 5 камерами. Симптомами этой проблемы для меня было то, что мое приложение зависало при запуске AVCamViewController после съемки около 5-10 фотографий.

Я запустил приложение через профилировщик утечек памяти, и никаких явных утечек не было, но при проверке с помощью Activity Monitor я обнаружил, что то, что называется mediaserverd, увеличивается на 17 МБ при каждом запуске камеры и когда оно достигает ~ 100 МБ, приложение падает с несколькими предупреждениями о недостаточном объеме памяти.

Ответы [ 3 ]

16 голосов
/ 25 октября 2011

Первое, что я сделал, это включил регистрацию в методах dealloc всех файлов AVCam.Я быстро обнаружил, что AVCamCaptureManager и AVCamRecorder не были освобождены, когда был AVCamViewController.Я проверил вызовы retain и release, и они казались сбалансированными, поэтому я установил точку останова на [releaseManager release] и обнаружил, что он имел retainCount 2 ПОСЛЕ релиза (и, следовательно, вызов вызова AVCamCaptureManager не вызывался).

Затем я прошел процесс создания диспетчера захвата и обнаружил, что он имел счет сохранения 3 сразу после вызова метода init.

Переход по методу init и проверка количества храненияв каждой строке я обнаружил, что следующие две строки увеличивали счетчик хранения:

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

Просматривая, я обнаружил, что дубликаты removeObserver были ВНУТРИ метода dealloc объекта AVCamCaptureManager (который не вызывался) итаким образом, количество сохраняемых данных никогда не уменьшалось до 0.

Чтобы исправить это, я создал новый общедоступный метод removeObservers:

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

и извлек те же строки из метода dealloc AVCamCaptureManager.

Вызов [captureManager removeObservers];и ТО вызывая [captureManager release];в методе dealloc AVCamViewController значение счетчика успешно удаляется до 0.

При тестировании с помощью Activity Monitor процесс mediaserverd гудит всего на 5-17 Мб, и сбой прекращается!

Надеюсь, это кому-нибудь поможетеще с этой проблемой!

4 голосов
/ 01 ноября 2013

Apple пересмотрела образец кода 17 октября 2013 года, исправив цикл сохранения.Проблема связана с неправильным использованием self в блоках, определенных в init.

. Вот описание редакции

Исправлены циклы сохранения в AVCaptureManager, что приводит кв утечках. ПРИМЕЧАНИЕ - если вы адаптировали код AVCam в своем приложении, вы должны принять исправления, сделанные здесь в методе AVCaptureManager.m init.Без этих исправлений вы можете пропустить AVCaptureManager экземпляров и оставить камеру постоянно включенной, пока ваше приложение находится на переднем плане.


Однако , исправление, которое они представилиработает только в случае ручного сохранения счета.Если вы используете ARC в проекте, кроме избавления от вызовов release / retain и других очевидных вещей, квалификатор хранилища для weakSelf должен быть изменен с __block на __weak, как показано ниже.

__weak AVCamCaptureManager *weakSelf = self;

На самом деле семантика __block изменилась с ARC.В MRC это вызвало слабую ссылку на переменную, тогда как в ARC это не так, и __weak должен использоваться для этой цели.

Более подробную информацию по этой теме можно найти здесь: Как мнеизбежать захвата себя в блоках при реализации API?

Использование новой реализации init из последней ревизии и использование __weak вместо __block, наконец, привело к тому, что метод dealloc был


Наконец, для тех, кто ненавидит переносить старый унаследованный код, вот модернизированная версия проекта AVCam: https://github.com/Gabro/AVCam

Особенности:

  • утечки памяти
  • использует ARC
  • современный синтаксис Objective-C
  • незначительные исправления пользовательского интерфейса для iOS 7
2 голосов
/ 19 июля 2013

Недавно столкнулся с этой проблемой. Я обнаружил, что настоящая корневая проблема заключается в том, что deviceConnectedBlock и deviceDisconnectedBlock неявно ссылаются на себя, что приводит к сохранению циклов. Чтобы исправить это, измените все ссылки на ivar в этих блоках, чтобы использовать weakSelf.

Таким образом, вам не нужно будет явно вызывать метод разрыва.

Надеюсь, это поможет кому-то еще.

REF: Просмотр освобождения контроллера не вызывается при использовании метода кодового блока NSNotificationCenter с ARC

...