Предупреждение о низком уровне памяти AVCam

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

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


person Red Nightingale    schedule 17.10.2011    source источник
comment
Спасибо! Разделите ответ на ответ, который вы затем сможете принять: Этикет для ответа на ваш собственный вопрос и публикация и отвечая на вопросы, на которые вы уже нашли ответ   -  person sehe    schedule 17.10.2011
comment
Пытался, но поскольку я не премиум-пользователь, это не позволило мне ответить на мой собственный вопрос в течение 24 часов ... не было времени возиться с этим (или забыть то, что я хотел записать) ... Я Посмотрим, смогу ли я это сделать сейчас.   -  person Red Nightingale    schedule 25.10.2011


Ответы (3)


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

Вот описание ревизии

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


Однако введенное ими исправление работает только в случае ручного подсчета удержания. Если вы используете ARC в проекте, помимо избавления от вызовов _8 _ / _ 9_ и других очевидных вещей, квалификатор хранилища для 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
person Gabriele Petronella    schedule 01.11.2013
comment
Привет, Габриэле, я просмотрел ваш проект AVCam. Вы можете изменить комментарий «ARC-совместимый» на «ARC эксклюзивный»? Я добавил его в свой проект, не относящийся к ARC, и есть некоторые сбои компиляции, связанные с использованием эксклюзивных функций ARC. - person Red Nightingale; 02.11.2013
comment
@RedNightingale Абсолютно ужасный выбор слов. Кстати, вы можете выборочно включить ARC для определенных файлов даже в проекте, отличном от ARC, если хотите. Надеюсь, это поможет. - person Gabriele Petronella; 02.11.2013
comment
Я займусь этим. Опробовали новые версии кода Apple, и они, похоже, наконец-то работают правильно, поэтому я предлагаю это как ответ. - person Red Nightingale; 03.11.2013
comment
Если можете, используйте код Габриэле AVCam. Если вы редактируете более раннюю версию AVCam в существующем проекте, обязательно измените метод инициализации, чтобы использовать weakSelf везде, где вам нужно. Если у вас все еще есть проблемы, начните проверять keepCounts для себя в конце метода инициализации. Если вы видите keepCounts, которые не имеют смысла, вы пропустили преобразование чего-либо для использования weakSelf. - person russes; 25.12.2013
comment
определенно все еще утечка памяти при запуске демонстрации Apple на iOS 9, эти обновления все еще исправляют - person Cbas; 20.07.2016

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

Затем я прошел через процесс создания диспетчера захвата и обнаружил, что он имеет счетчик сохранения 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 (который не вызывался), и поэтому счетчик сохранения никогда не опускался до 0.

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

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

и выведение тех же строк из метода освобождения AVCamCaptureManager.

Вызов [captureManager removeObservers]; и ЗАТЕМ вызов [releaseManager release]; в методе освобождения AVCamViewController успешно сбрасывает счетчик удержания до 0.

Тестирование с помощью монитора активности теперь показывает, что процесс mediaserverd гудит всего на 5-17 МБ, и сбой прекращается!

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

person Red Nightingale    schedule 25.10.2011
comment
Лучше ... могущественные ТАК боги позволили мне теперь ответить на мой собственный вопрос;) - person Red Nightingale; 25.10.2011
comment
Могущественные боги SO позволили мне поблагодарить меня, поставив мне +1;) - person sehe; 25.10.2011
comment
Хорошее описание. Я считаю, что мы столкнулись с той же проблемой. - person Clay Bridges; 02.11.2011
comment
Большое спасибо! У нас возникла та же проблема. - person nicolas; 13.12.2011
comment
замечательно, если бы я мог купить вам пиво в Интернете, я бы! - person Ben; 31.05.2012
comment
@RedNightngale Привет, я только что столкнулся с этой проблемой и считаю, что наконец-то доступно менее хакерское решение. Проверьте мой ответ;) - person Gabriele Petronella; 01.11.2013

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

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

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

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

person Chen Lim    schedule 19.07.2013
comment
У меня была одна ссылка на себя в блоке. Я заменил это на weakSelf и вернулся к «нормальному» коду выпуска AVCAM. CaptureManager все еще не вызывает dealloc. Статья, на которую вы ссылаетесь, относится к __weak для справки, однако это применимо только к коду ARC (который я в настоящее время не использую). Вместо этого мне нужно использовать __block, но я недостаточно понимаю «блоки», чтобы иметь возможность предложить эквивалентное решение, которое работает. - person Red Nightingale; 19.07.2013