Diversi algoritmi GC hanno diversi compromessi. Alcuni ottimizzano per un throughput elevato, altri per bassa latenza. Non esiste un singolo algoritmo migliore, quindi le piattaforme come la JVM Hotspot sono molto sintonizzabili e consentono di selezionare un profilo che si adatta al carico di lavoro previsto. Un buon algoritmo GC proverà ad auto-sintonizzarsi sul carico di lavoro effettivo, ma ovviamente ciò si ripaga solo per processi di lunga durata. Gli algoritmi GC moderni spesso funzionano anche in un thread separato per ridurre al minimo le pause, ma ciò comporta un sovraccarico della CPU più elevato.
Il conteggio dei conti non è una soluzione particolarmente interessante quando guardiamo i numeri. È a bassa velocità, ha tempi di pausa illimitati e ha un sovraccarico di memoria per oggetto gestito. Ma a differenza dei normali algoritmi GC, consente la distruzione deterministica (ad esempio modelli come RAII in C ++). Ciò lo rende interessante quando vogliamo anche gestire risorse non di memoria come gli handle di file, senza doverli chiudere esplicitamente o dover utilizzare una sintassi speciale come using
(C #), try-with-resource (Java), o with
(Python). È anche facile adattarsi retroattivamente a un sistema esistente, specialmente quando si vuole mescolare un non gestito con la memoria gestita. Pertanto, Objective-C (qualsiasi oggetto), C ++ ( std::shared_ptr
) e Rust ( Rc
, Arc
) consentono di (esplicitamente) opt-in per il conteggio. Il conteggio manuale è un modello comune nelle API C. Quindi è uno schema meraviglioso che non sarà spostato da altri algoritmi, ma le sue prestazioni non sono competitive con il GC più avanzato.
Il documento che hai citato mostra che RC può essere competitivo nel tracciare GC, ma sembra che non stiano usando la distruzione deterministica. In base a questo vincolo rilassato e con il supporto di un runtime JVM, sono in grado di ottenere significative ottimizzazioni. Questo è inapplicabile nella maggior parte degli scenari in cui RC è attualmente in uso.