2011-10-17 19 views
7

Esto es menos una pregunta y más un registro de lo que he encontrado en torno al código de muestra AVCam proporcionado por Apple para iOS4 y 5 manipulación de la cámara. Los síntomas del problema para mí fueron que mi aplicación fallaría al iniciar AVCamViewController después de tomar alrededor de 5-10 fotos.AVCam memory low warning

Ejecuté la aplicación a través del generador de perfiles de fuga de memoria y no aparecieron fugas pero en la inspección con Activity Monitor descubrí que algo llamado mediaserverd aumentaba en 17Mb cada vez que se iniciaba la cámara y cuando alcanzaba ~ 100Mb la aplicación se estrelló con múltiples advertencias de memoria baja.

+0

¡Gracias! Por favor divida la respuesta en una respuesta, que luego puede aceptar: [Etiqueta para responder su propia pregunta] (http://meta.stackexchange.com/questions/17845/etiquette-for-answering-your-own-question) y [Publicando y respondiendo preguntas a las que ya has encontrado la respuesta] (http://meta.stackexchange.com/questions/2706/posting-and-answering-questions-you-have-already-found-the-answer-to) – sehe

+0

Intenté eso, pero como no soy un usuario premium, no me dejaba responder mi propia pregunta en 24 horas ... no tenía tiempo para meterme con ella (u olvidar lo que quería grabar) ... Veré si puedo hacerlo ahora. –

Respuesta

4

de Apple revisó el código de ejemplo, el 17 oct 2013, que fija el ciclo de retener. El problema se debe a un uso incorrecto de self dentro de los bloques definidos en el init.

He aquí la descripción de revisión

fijo retener ciclos en AVCaptureManager que dan lugar a fugas. NOTA - si ha adaptado el código AVCam en su aplicación, debe adoptar las correcciones realizadas aquí en el método AVCaptureManager.minit. Sin estas correcciones, es posible que esté filtrando instancias de AVCaptureManager y deje la cámara funcionando constantemente mientras su aplicación está en primer plano.


Sin embargo, la solución se introdujo sólo funciona en el caso de manual Conservar Conde. Si está utilizando ARC en el proyecto, además de deshacerse de llamadas release/retain y otras cosas obvias, el calificador de almacenamiento para weakSelf tiene que ser cambiado de __block a __weak, como se indica a continuación.

__weak AVCamCaptureManager *weakSelf = self; 

De hecho, la semántica de __block cambió con ARC. En MRC provocó que la variable se referenciara débilmente, en ARC no es así y __weak se debe utilizar para este fin.

Más información sobre este tema se puede encontrar aquí: How do I avoid capturing self in blocks when implementing an API?

Usando el nuevo init aplicación de la última revisión y el uso de __weak en lugar de __block, finalmente causó el método dealloc a ser llamado correctamente.


Por último, para los que odian a llevar alrededor de código heredado de edad, he aquí una versión modernizada del proyecto AVCam: https://github.com/Gabro/AVCam

Características:

  • pérdidas de memoria libre
  • utiliza ARC
  • moderno sintaxis Objective-C
  • minor UI correcciones para iOS 7
+0

Hola Gabriele, he echado un vistazo a tu proyecto AVCam. ¿Puede cambiar el comentario 'ARC compatible' a 'ARC exclusivo'? Lo he agregado a mi proyecto que no es de ARC y hay algunos errores de compilación relacionados con el uso de la funcionalidad exclusiva de ARC. –

+0

@RedNightingale Absolutamente, terrible elección de palabras de hecho. Por cierto, puede habilitar selectivamente ARC en archivos específicos, incluso en un proyecto que no sea ARC, si lo desea. Espero eso ayude. –

+0

Voy a investigar eso. He probado las nuevas revisiones del código de Apple y parece que finalmente están funcionando correctamente, así que promocionaré esta para ser la respuesta. –

16

Lo primero que hice fue poner el registro en los métodos dealloc de todos los archivos AVCam. Descubrí rápidamente que AVCamCaptureManager y AVCamRecorder no estaban siendo desasignados cuando estaba el AVCamViewController. Revisé las llamadas de retención y liberación y parecían equilibrarse, así que puse un punto de interrupción en la versión de [captureManager] y descubrí que tenía una retención de 2 DESPUÉS del lanzamiento (y por lo tanto, no se llamaba al dealloc de AVCamCaptureManager).

Siguiente Pasé por el proceso de creación para el administrador de captura y descubrí que tenía un conteo de retención de 3 inmediatamente después de que se llamara el método init.

Entrar por el método init y el control de la cuenta de retención en cada línea descubrí las dos líneas siguientes fueron tanto incrementando la cuenta de retención:

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

Mirando a través encontré que las contrapartes removeObserver estaban dentro del método dealloc del AVCamCaptureManager (que no estaba siendo llamado) y por lo que la cuenta de retención nunca se redujo a 0.

para solucionarlo he creado un nuevo método removeObservers públicos:

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

y tomando las mismas líneas OUT del método dealloc AVCamCaptureManager.

Llamando [captureManager removeObservers]; y ENTONCES llamando a [release de captureManager]; en el método AVCamViewController dealloc se elimina con éxito el recuento de retención a 0.

Las pruebas con el Monitor de actividad ahora tienen el proceso de mediaserverd zumbando a solo 5-17Mb ¡y el bloqueo se detiene!

Espero que esto ayude a cualquier otra persona que tenga este problema!

+1

Mejor ... los poderosos dioses SO me han permitido responder mi propia pregunta ahora;) –

+0

Los poderosos dioses SO me han permitido decir gracias dándole mi +1;) – sehe

+0

Buena descripción. Creo que llegamos a este mismo problema. –

2

Se encontró con este problema recientemente. Descubrí que el verdadero problema de raíz era que deviceConnectedBlock y deviceDisconnectedBlock se referían implícitamente a self, lo que llevaba a retener ciclos. Para solucionarlo, cambie todas las referencias ivar en esos bloques para usar weakSelf.

De esta forma, no tendrá que recordar llamar explícitamente a un método de desmontaje.

Espero que esto ayude a alguien más.

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

+0

Tuve una referencia a mí mismo en el bloque.Reemplacé eso con weakSelf y volví al código de liberación 'normal' de AVCAM. CaptureManager todavía no está llamando a dealloc. El artículo al que se ha vinculado se refiere a __weak como referencia, pero esto solo se aplica al código ARC (que actualmente no estoy usando). Necesito usar __block pero no entiendo lo suficiente sobre 'blocks' para poder encontrar una solución equivalente que funcione. –