Предупреждение о низком уровне памяти AVCam
Это не вопрос, а скорее запись того, что я нашел вокруг примера кода AVCam, предоставленного Apple для iOS4 и манипуляции с 5 камерами. Симптомами этой проблемы для меня было то, что мое приложение зависало при запуске AVCamViewController после съемки 5-10 фотографий.
Я запустил приложение через профилировщик утечек памяти, и не было никаких явных утечек, но при проверке с помощью Activity Monitor я обнаружил, что то, что называется mediaserverd, увеличивалось на 17 МБ при каждом запуске камеры и когда оно достигало ~100 МБ, приложение вылетало с несколькими низкими Память предупреждений.
3 ответа
Apple пересмотрела образец кода 17 октября 2013 года, исправив цикл сохранения. Проблема связана с неправильным использованием self
в пределах блоков, определенных в init
,
Вот описание ревизии
Исправлено сохранение циклов в
AVCaptureManager
что приводит к утечкам. ПРИМЕЧАНИЕ - если вы адаптировалисьAVCam
код в вашем приложении, вы должны принять исправления, сделанные здесь вAVCaptureManager.m
"sinit
метод. Без этих исправлений вы можете просочиться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 в этих блоках, чтобы использовать слабый_себель.
Таким образом, вам не нужно будет явно вызывать метод разрыва.
Надеюсь, это поможет кому-то еще.