2011-10-17 12 views
7

Questa è meno una domanda e più una registrazione di ciò che ho trovato intorno al codice di esempio di AVCam fornito da Apple per la manipolazione delle telecamere iOS4 e 5. I sintomi del problema per me erano che la mia app si arrestava in modo anomalo all'avvio di AVCamViewController dopo aver scattato circa 5-10 foto.Avviso di memoria AVC basso

Ho eseguito l'app attraverso il profiler della perdita di memoria e non ci sono state perdite apparenti ma in seguito all'ispezione con Activity Monitor ho scoperto che qualcosa chiamato mediaserverd aumentava di 17 Mb ogni volta che la fotocamera veniva lanciata e quando raggiungeva ~ 100Mb l'app si è schiantato con più avvisi di memoria insufficiente.

+0

Grazie! Si prega di dividere la risposta in una risposta, che è possibile quindi accettare: [Etichetta per rispondere alla propria domanda] (http://meta.stackexchange.com/questions/17845/etiquette-for-answering-your-own-question) e [Postando e rispondendo alle domande che hai già trovato la risposta a] (http://meta.stackexchange.com/questions/2706/posting-and-answering-questions-you-have-already-found-the-answer-to) – sehe

+0

Provato questo, ma visto che non sono un utente premium, non mi permetterebbe di rispondere alla mia domanda entro 24 ore ... non ho avuto il tempo di scherzare (o dimenticare quello che volevo registrare) ... Vedrò se posso farlo ora. –

risposta

4

Apple ha rivisto il codice di esempio il 17 ottobre 2013, che fissa il ciclo di trattenere. Il problema è dovuto a un uso improprio di self all'interno dei blocchi definiti nello init.

Ecco la descrizione revisione

fisso trattenere cicli AVCaptureManager che provocano perdite. NOTA - se hai adattato il codice AVCam nella tua app, dovresti adottare le correzioni apportate qui nel metodo init . Senza queste correzioni, è possibile che si verifichino perdite di istanze di AVCaptureManager e che la fotocamera funzioni costantemente mentre l'app è in primo piano.


Tuttavia, la correzione hanno introdotto funziona solo in caso di manuale Conservare Conte. Se si sta utilizzando ARC sul progetto, oltre a eliminare le chiamate release/retain e altre cose ovvie, il qualificatore di memoria per weakSelf deve essere modificato da __block a __weak, come segue.

__weak AVCamCaptureManager *weakSelf = self; 

Infatti la semantica di __block è stata modificata con ARC. In MRC ha causato il deferimento della variabile, mentre in ARC non lo fa e __weak deve essere usato per questo scopo.

Maggiori informazioni su questo argomento si possono trovare qui: How do I avoid capturing self in blocks when implementing an API?

Utilizzando la nuova implementazione init dall'ultima revisione e l'utilizzo di __weak invece di __block, infine, ha causato il metodo dealloc da chiamare in modo corretto.


Infine, per coloro che odiano a portare in giro il vecchio codice legacy, ecco una versione modernizzata del progetto AVCam: https://github.com/Gabro/AVCam

Caratteristiche:

  • perdite di memoria libera
  • usa le ARC
  • sintassi moderna Objective-C
  • interfaccia utente minore correzioni per iOS 7
+0

Ciao Gabriele, ho dato un'occhiata al tuo progetto AVCam. È possibile modificare il commento "ARC compatibile" con "ARC exclusive"? L'ho aggiunto al mio progetto non ARC e ci sono alcuni errori di compilazione relativi all'uso della funzionalità esclusiva di ARC. –

+0

@RedNightingale Assolutamente, terribile scelta di parole davvero. Tra l'altro, puoi abilitare in modo selettivo l'ARC su file specifici anche in un progetto non ARC, se vuoi. Spero che sia d'aiuto. –

+0

Lo esaminerò. Hanno provato le nuove revisioni del codice Apple e sembrano finalmente funzionare correttamente, quindi promuoverò che questa sia la risposta. –

16

La prima cosa che ho fatto è stata la registrazione nei metodi dealloc di tutti i file AVCam. Ho scoperto rapidamente che AVCamCaptureManager e AVCamRecorder non erano stati deallocati quando AVCamViewController era. Ho controllato la conservazione e rilasciato le chiamate e sembravano bilanciate, quindi ho inserito un punto di interruzione nella [versione captureManager] e ho scoperto che aveva un retainCount di 2 DOPO la versione (e quindi il dealloc di AVCamCaptureManager non veniva chiamato).

Successivamente ho passato il processo di creazione per il gestore di cattura e ho scoperto che aveva un conteggio di ritenzione di 3 immediatamente dopo la chiamata del metodo init.

Facendo un passo attraverso il metodo init e controllando il conteggio mantengono su ogni riga ho scoperto i seguenti due linee sono state sia incrementare il conteggio conservano:

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

Guardando attraverso Ho trovato che le controparti removeObserver erano all'interno del metodo dealloc del AVCamCaptureManager (che non veniva chiamato) e così il conteggio di conservare mai sceso a 0.

per risolvere il problema ho creato un nuovo metodo removeObservers pubblici:

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

e prendere le stesse linee FUORI dal metodo dealloc di AVCamCaptureManager.

Chiamare [captureManager removeObservers]; e POI chiamando [captureManager release]; nel metodo dealloc di AVCamViewController con successo il conteggio dei ritardi a 0.

I test con Activity Monitor ora hanno il ronzio del processo mediaserverd a soli 5-17Mb e l'arresto anomalo!

Spero che questo aiuti chiunque altro abbia questo problema!

+1

Meglio ... i potenti SO di oggi mi hanno permesso di rispondere alla mia stessa domanda ora;) –

+0

I potenti SO di oggi mi hanno permesso di dire grazie dandogli il mio +1;) – sehe

+0

Buona descrizione. Credo che abbiamo raggiunto lo stesso problema. –

2

Recentemente risolto questo problema. Ho scoperto che il vero problema di root era che deviceConnectedBlock e deviceDisconnectedBlock si riferivano implicitamente a self, portando a cicli di conservazione. Per sistemarlo, cambia tutti i riferimenti di ivar in quei blocchi per usare weakSelf.

In questo modo, non è necessario ricordare di chiamare un metodo di smistamento esplicito.

Spero che questo aiuti qualcun altro.

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

+0

Ho avuto un riferimento a me stesso nel blocco.L'ho sostituito con weakSelf e ripristinato il normale codice di rilascio di AVCAM. CaptureManager non sta ancora chiamando dealloc. L'articolo a cui ti sei collegato fa riferimento a __bordo per il riferimento, tuttavia questo è applicabile solo al codice ARC (che attualmente non utilizzo). Ho invece bisogno di usare __block ma non capisco abbastanza dei 'blocchi' per riuscire a trovare una soluzione equivalente che funzioni. –