Il consenso sulla RC vs tracing in ricerca informatica è stata, per lungo tempo, che ha tracciato il throughput della CPU superiore, nonostante più volte (massimo) di pausa. (Per esempio.vedi here, here e here.) Solo molto recentemente, nel 2013, è stato pubblicato un documento (ultimo collegamento sotto questi tre) che presenta un sistema basato su RC che offre prestazioni uguali o un po 'migliori rispetto al GC di tracciamento migliore, per quanto riguarda Throughput della CPU. Inutile dire che non ha ancora implementazioni "reali".
Ecco un piccolo punto di riferimento ho appena fatto sul mio iMac con 3.1 i5 GHz, in iOS 7.1 a 64 bit simulatore:
long tenmillion = 10000000;
NSTimeInterval t;
t = [NSDate timeIntervalSinceReferenceDate];
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:tenmillion];
for (long i = 0; i < tenmillion; ++i)
[arr addObject:[NSObject new]];
NSLog(@"%f seconds: Allocating ten million objects and putting them in an array.", [NSDate timeIntervalSinceReferenceDate] - t);
t = [NSDate timeIntervalSinceReferenceDate];
for (NSObject *obj in arr)
[self doNothingWith:obj]; // Can't be optimized out because it's a method call.
NSLog(@"%f seconds: Calling a method on an object ten million times.", [NSDate timeIntervalSinceReferenceDate] - t);
t = [NSDate timeIntervalSinceReferenceDate];
NSObject *o;
for (NSObject *obj in arr)
o = obj;
NSLog(@"%f seconds: Setting a pointer ten million times.", [NSDate timeIntervalSinceReferenceDate] - t);
Con ARC disabilitato (-fno-objc-arc
), questo ha pronunciato la seguente:
2.029345 seconds: Allocating ten million objects and putting them in an array.
0.047976 seconds: Calling a method on an object ten million times.
0.006162 seconds: Setting a pointer ten million times.
Con ARC abilitato, che diventa:
1.794860 seconds: Allocating ten million objects and putting them in an array.
0.067440 seconds: Calling a method on an object ten million times.
0.788266 seconds: Setting a pointer ten million times.
A quanto pare l'allocazione obje i metodi di chiamata e di chiamata sono diventati in qualche modo più economici. L'assegnazione a un puntatore di oggetto è diventata più costosa per ordini di grandezza, sebbene non si dimentichi che non ho chiamato -retain nell'esempio non ARC e si noti che è possibile utilizzare __unsafe_unretained
se si dispone di un hotspot che assegna puntatori di oggetti come pazzi. Ciononostante, se si vuole "dimenticare" la gestione della memoria e lasciare che ARC inserisca le chiamate di mantenimento/rilascio dove vuole, si sprecheranno, nel caso generale, molti cicli CPU, ripetutamente e in tutti i percorsi di codice che impostano i puntatori. D'altra parte un GC tracciante lascia il tuo codice da solo, e solo a calci in momenti selezionati (di solito quando si assegna qualcosa), facendo la sua cosa in un colpo solo. (Naturalmente i dettagli sono un molto più complicato in verità, dato GC generazionale, GC incrementale, GC concorrente, ecc)
Quindi sì, dal momento RC di Objective-C utilizza atomica mantenere/release, è piuttosto costoso ma Objective-C ha anche molte più inefficienze di quelle imposte dal Refcounting. (Ad esempio, la natura completamente dinamica/riflessiva dei metodi, che può essere "inondata" in qualsiasi momento dal run-time, impedisce al compilatore di eseguire molte ottimizzazioni incrociate che richiederebbero l'analisi del flusso di dati e così via. Un objc_msgSend () è sempre una chiamata a una black box "collegata dinamicamente" dalla vista dell'analizzatore statico, per così dire.) Tutto sommato, l'Objective-C come linguaggio non è esattamente il più efficiente o il meglio ottimizzato in circolazione; la gente lo chiama "sicurezza di tipo C con la velocità fulminante di Smalltalk" per una ragione. ;-)
Durante la scrittura di Objective-C, quello generalmente solo strumenti intorno ben implementati librerie di Apple, che utilizzano sicuramente C e C++ e montaggio o qualsiasi altra cosa per i loro hotspot. Il tuo codice raramente ha bisogno di essere efficiente. Quando c'è un punto caldo, puoi renderlo molto efficiente scendendo verso i costrutti di basso livello come il puro codice in stile C all'interno di un singolo metodo Objective-C, ma raramente ne hai mai bisogno. Ecco perché Objective-C può sostenere il costo dell'ARC nel caso generale. Non sono ancora convinto che tracciare GC abbia problemi di inerenti a in ambienti con limitazioni di memoria e pensare che si possa usare un linguaggio di alto livello per strumentare anche le librerie, ma a quanto pare RC si trova meglio con Apple/iOS. Si deve considerare l'intero quadro che hanno costruito finora e tutte le loro librerie legacy quando si chiedono perché non sono andati con un GC di tracciamento; per esempio ho sentito che RC è piuttosto profondamente integrato in CoreFoundation.
"numerose istruzioni aggiuntive" - numero == uno; 'INC [esp + 12]'. Inoltre, Objective-C utilizza un assembly sintonizzato a mano ed è anche un linguaggio compilato => veloce. –
ha bisogno di un prefisso LOCK su quell'INC e non tiene conto della tabella laterale di objc e supporto degli strumenti –
Non sarei d'accordo, il conteggio dei riferimenti è un modo molto efficace per gestire le complessità della gestione manuale della memoria. Non è adatto a tutte le situazioni, ma le prestazioni e il controllo rendono superfluo qualsiasi garbage collection. –