2009-09-05 19 views
13

ho giocato un po 'di tempo con diverse build della mia applicazione e sembrano accadere cose strane:i file binari a 64 bit del cacao perdono memoria? (Rilasciando NSData non libera memoria)

la mia app ha un ingombro di 5 MB inattivo. quando si carica una memoria di file di dimensioni del file è riservata. dopo il caricamento la memoria riservata deve essere liberata. Non vi sono differenze nella costruisce (gc = garbage collector):

  • 32bit i386 no-GC: tutta la memoria viene liberato immediatamente.
  • GC i386 a 32 bit: quasi tutta la memoria viene liberata all'istante. il resto qualche tempo dopo.
  • 64 bit x86_64 no-GC: la memoria minima viene liberata. come 10%
  • 64 bit x86_64 GC: nessuna memoria viene liberata. la memoria rimane riservata per ore. (attività mon)

sto utilizzando LLVM con CLANG. Ho eseguito gli strumenti di oggi tutto il tempo e stavo controllando perdite/zombi/ecc. e tutto sembra essere pulito. (l'app è piuttosto semplice)

c'è una spiegazione per questo comportamento?


Aggiornamento:

Ecco alcune cose strane. Ho risolto il problema:

Carico un file 20mb in un NSData e lo rilascio. Lo sto facendo senza abilitare la garbage collection. Il codice è:

NSData *bla = [[NSData alloc] initWithContentsOfFile:@"/bigshit"]; 
[bla release]; 

Quando costruisco per i386 32bit, i 20mb vengono allocati e rilasciati. Quando cambio la build su 64bit x86_64 il rilascio non fa nulla. Il soggiorno di 20mb è stato assegnato.

upper pic 32bit lower 64 http://kttns.org/zguxn

Non c'è differenza tra le due applicazioni, tranne che quello superiore è costruito per 32bit e quello inferiore 64 bit. Non c'è GC in esecuzione. (Con GC abilitata appare lo stesso problema.)


Aggiornamento 2:

lo stesso comportamento può essere osservato quando creo una nuova applicazione di cacao da zero con solo il codice in alto a applicationDidFinishLaunching :. In modalità 64 bit la memoria non viene rilasciata. i386 funziona come previsto.

Lo stesso problema si verifica con NSString anziché NSData. Appare anche quando avvio il kernel a 64 bit. (Tenendo 64 all'avvio.)

OS è 10.6.0

+0

Si è tentato di allocare e deallocare molte istanze NSData per vedere se la memoria perché qualcuno di loro è reclamato? Potrebbe essere che il programma non restituisca la memoria al sistema operativo a meno che non vi sia una carenza di memoria. – Amok

+0

Ho appena provato a riprodurlo su 10.6 senza fortuna. Hai archiviato un bug con la tua app di test? – Ken

+0

La tua app funziona correttamente e non perde memoria. Vedi la mia risposta qui sotto per una spiegazione semi-dettagliata. – bbum

risposta

10

Innanzitutto, utilizzare lo strumento grafico a oggetti dello strumento per verificare che la memoria non sia più considerata in uso; non ha un numero di ritenzione o un riferimento forte da qualche parte.

Se non è più in uso, la memoria si blocca semplicemente perché non si è raggiunta la soglia a cui il collettore si prende cura.

Tuttavia, questa affermazione:

64bit x86_64 no-GC: il minimo è liberato. come 10%

Mi fa attenzione. Specificamente, se il tuo codice è progettato per funzionare in non GC - con retain/release - allora (a) hai una perdita di memoria e, se usi CFRetain o qualche tipo di cache globale, questo potrebbe avere un impatto su GC o (b) non stai utilizzando gli strumenti giusti per capire se hai o meno una perdita di memoria.

Quindi, come stai determinando che stai perdendo memoria?

Aggiornamento; stai usando Activity Monitor per monitorare il RSIZE/VSIZE del processo. Questo in realtà non ti dirà niente di utile oltre "il mio processo cresce nel tempo".

Più probabile che no (non ho guardato alla fonte), questo codice:

NSData *bla = [[NSData alloc] initWithContentsOfFile:@"/bigpoop"]; 

causerà il file 20MB di essere mmap() 'd per il processo. Non c'è affatto un'allocazione stile malloc(). Invece, il sistema operativo consegna 20MB di spazio di indirizzamento contiguo al processo e mappa i contenuti del file in esso. Mentre leggi il contenuto dell'NSData, il file verrà visualizzato nel file man mano che procedi.

Quando si rilascia bla, la mappatura viene distrutta. Ma ciò non significa che il sottosistema VM ridurrà lo spazio degli indirizzi dell'applicazione di 20 MB.

Quindi, stai bruciando un po 'di spazio di indirizzamento, ma non la memoria reale. Poiché il tuo processo è a 64 bit, lo spazio degli indirizzi è praticamente una risorsa infinita e il costo dell'uso degli indirizzi è molto basso, motivo per cui il sistema operativo è implementato in questo modo.

I.e. non ci sono perdite e la tua app si comporta correttamente, GC o no.

Questo è un malinteso comune e, quindi, ha fatto la domanda.

+0

Sto usando gli strumenti di perdita di memoria. E come una costruzione a 32 bit tutto funziona come previsto. – jsz

+0

per favore leggi i miei aggiornamenti alla domanda originale. – jsz

+0

grazie per la risposta. sembra che tu abbia ragione :) – jsz

2

spazzino non necessariamente rilascia la memoria immediatamente.

In caso di Objective-C garbage collector, è possibile inviare garbage collector di cacao oggetto un messaggio collectIfNeeded suggerire che ora può essere un buon momento per fare un po 'di raccolta, o collectExhaustively ordinarlo per iniziare immediatamente la raccolta di ogni e tutta spazzatura (ma anche questa è interrompibile). Vedi the docs.

0

Ho un problema molto simile in iPhoneOS 3.2 e davvero non credo che la memoria venga recuperata - alla fine faccio scattare avvertenze sulla memoria. C'è una piccola possibilità che ho trascurato un mio errore ma sono stato molto approfondito.

Uso l'unarchiveObjectWithFile di NSKeyedUnarchiver: per caricare un oggetto personalizzato che contiene un singolo NSData di grandi dimensioni e un altro oggetto molto più piccolo. Il metodo dealloc nel mio oggetto personalizzato viene chiamato, l'oggetto NSData viene rilasciato, il suo retainCount == 1 poco prima. La memoria fisica non diminuisce di qualsiasi importo, per non parlare di una frazione della dimensione NSData, e con gli avvisi della memoria di ripetizione vengono generati in modo affidabile: ho eseguito il test finché non ho ricevuto effettivamente avvertimenti di livello 2.= (

prima della commercializzazione:

(gdb) p (int) [(NSData *) pastItsWelcomeData retainCount]
$ 1 = 1

Dopo il rilascio:

(gdb) p (int) [(NSData *) pastItsWelcomeData retainCount]
L'obiettivo non risponde a questo selettore di messaggi

+0

Hai un altro problema. GC non esiste su iPhone e 'retainCount' è la cosa sbagliata da utilizzare per il debug dei problemi di durata dell'oggetto. (Usa invece gli strumenti.) Poiché questa è una descrizione di un problema diverso e non risponde alla domanda, devi pubblicarla come una domanda separata. –

Problemi correlati