2010-11-02 5 views
6

O il mio debugger è rotto o c'è qualcosa di fondamentale che non sto capendo.Sovraccarico Objective-C semplice che * dovrebbe * crash non si blocca. Perché?

Ho un codice molto semplice in un programma di riga di comando molto elementare che dovrebbe causare un arresto anomalo di. Tuttavia, non si blocca.

int main (int argc, const char * argv[]) 
{ 
    NSString *string = [[NSString alloc] initWithString:@"Hello"]; 

    [string release]; 

    NSLog(@"Length: %d", [string length]); 

    return 0; 
} 

L'stampe log dichiarazione "Lunghezza: 5" come ci si aspetterebbe per una stringa valida. Tuttavia, la stringa deve essere deallocata da quel punto e deve essere generato un errore exec_bad_access.

Ho provato questo codice con il debugger allegato e senza il debugger allegato - entrambi danno lo stesso risultato. Ho anche abilitato (e disabilitato) NSZombie, che sembra non avere alcun effetto (inizialmente pensavo che questo fosse il problema, dal momento che gli oggetti NSZombie non sono mai stati deallocati - ma non si blocca ancora con NSZombie disabilitato).

Sono presenti dei punti di interruzione nel file locale .gdbinit per interromperli, ad esempio -[NSException raise] e objc_exception_throw. Ho anche dei punti di interruzione impostati su molti metodi su NSZombie per catturarli.

fb -[NSException raise] 
fb -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] 
fb -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] 

#define NSZombies 
# this will give you help messages. Set to NO to turn them off. 
set env MallocHelp=YES 
# might also be set in launch arguments. 
set env NSZombieEnabled=YES 
set env NSDeallocateZombies=NO 
set env MallocCheckHeapEach=100000 
set env MallocCheckHeapStart=100000 
set env MallocScribble=YES 
set env MallocGuardEdges=YES 
set env MallocCheckHeapAbort=1 

set env CFZombie 5 

fb -[_NSZombie init] 
fb -[_NSZombie retainCount] 
fb -[_NSZombie retain] 
fb -[_NSZombie release] 
fb -[_NSZombie autorelease] 
fb -[_NSZombie methodSignatureForSelector:] 
fb -[_NSZombie respondsToSelector:] 
fb -[_NSZombie forwardInvocation:] 
fb -[_NSZombie class] 
fb -[_NSZombie dealloc] 

fb szone_error 
fb objc_exception_throw 

Con queste impostare punti di interruzione e NSZombie abilitata, dovrei ottenere qualcosa di simile [NSString length]: message sent to deallocated instance 0x100010d39 stampata alla console, ma non vedo questo. Vedo il NSLog che stampa la lunghezza come 5.

Vedo un comportamento simile con altre classi come NSURL e NSNumber. Alcune classi si bloccano come previsto, ad esempio NSError e NSObject.

Questo ha qualcosa a che fare con i cluster di classe? Non seguono le stesse regole riguardo alla gestione della memoria?

Se i cluster di classe non sono correlati a questo problema, l'unica altra caratteristica comune che ho potuto vedere è che le classi che non si bloccano in questo modo sono tutte collegate senza ponte con una controparte Core Foundation. Questo potrebbe avere qualcosa a che fare con questo?

+0

Mi sono chiesto questo tempo fa, ho visto lo stesso 'problema'/comportamento. Spero che qualcuno possa spiegarlo. – Rits

+0

La raccolta dei dati inutili non è istantanea? :) – willcodejavaforfood

+1

Non è questo il punto. Nell'ambiente garbage collection, una chiamata esplicita a 'release' non fa assolutamente nulla. – Yuji

risposta

4

retain/release è un contratto tra l'API e il programmatore che quando si segue la regola, non si arresta in modo anomalo. Il contratto non garantisce che se non si segue la regola, si blocca!

In questo caso,

[[NSString alloc] initWithString:@"Hello"] 

solo restituisce lo stesso oggetto come @"Hello" come un'ottimizzazione. La costante NSString non viene mai rilasciata; come ottimizzazione, retain e release sono (penso) ignorati. Ecco perché non si blocca.

È possibile verificare le mie ipotesi confrontando il valore del puntatore di @"Hello" e string.

+0

Ok, questo ha senso per me. Che dire se ho fatto '[[NSString alloc] init];' al contrario di essere in coda con una stringa costante? Nei miei test, mostra ancora lo stesso comportamento dell'uso della stringa costante, è previsto anche questo? E gli altri casi in cui vedo lo stesso comportamento, come con 'NSURL' e' NSNumber'? – Jasarien

+0

E sì, sei corretto, stringa e @ "Ciao" puntano entrambi nella stessa posizione. Questo chiarisce. Comunque sono ancora confuso riguardo agli altri casi. – Jasarien

+0

'[[NSString alloc] init]' restituisce una stringa vuota condivisa, che non viene mai più distrutta. Non c'è alcuna garanzia che ogni chiamata a '[[SomeClass alloc] init]' fornisca un'istanza distinta. Il contratto prevede che se si segue la regola di conservazione/rilascio, il programma non si arresta in modo anomalo. Niente di più. – Yuji

1

Questo è un eccellente esempio del perché i conti di mantenimento sono uno strumento di debug piuttosto inutile. È un errore presupporre che -retain e -release aggiungano o rimuovano sempre 1 dal conteggio dei ritiri e che il conteggio dei ritiri sia ciò che si ritiene dovrebbe essere.

Prova

NSString *string = [[NSString alloc] initWithFormat:@"Hello %d", argc]; 

Questo dovrebbe darvi una stringa che si comporterà più come il modo in cui vi aspettate dal momento che non si è inizializzazione la stringa da una costante di tempo di compilazione. Tuttavia, tieni presente che, con gli zombi abilitati, otterrai il comportamento che ti aspetti, ma senza zombi, NSLog potrebbe funzionare correttamente. Sebbene la stringa sia stata deallocata, i dati nell'oggetto sono ancora presenti nella memoria, lasciando un "fantasma" che risponderà correttamente ad alcuni messaggi.

Problemi correlati