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

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

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

3 ответа

Решение

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

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

Исправлено сохранение циклов в AVCaptureManager что приводит к утечкам. ПРИМЕЧАНИЕ - если вы адаптировались AVCam код в вашем приложении, вы должны принять исправления, сделанные здесь в AVCaptureManager.m"s 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

Первое, что я сделал, - включил регистрацию в методах dealloc всех файлов AVCam. Я быстро обнаружил, что AVCamCaptureManager и AVCamRecorder не были освобождены, когда был AVCamViewController. Я проверил вызовы retain и release, и они казались сбалансированными, поэтому я установил точку останова на [captureManager 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 Мб, и сбой прекращается!

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

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

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

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

REF: просмотр не задействованного контроллера, когда используется метод блока кода NSNotificationCenter с ARC

Другие вопросы по тегам