La versione 2.1 di Ruby introduce un nuovo Garbage Collector, vediamo come funziona!
Come tutti sapete, l’azione del GC è divisa in due fasi:
- la fase di Mark, in cui viene esplorato dalla radice l’albero degli oggetti e viene settato il bit FL_MARK per indicare quelli “vivi”
- la fase di Sweep, in cui si itera sugli slot dell’heap e gli oggetti con il flag FL_MARK non settato vengono aggiunti alla lista degli oggetti disponibili (per il riutilizzo).
Durante le fasi di Mark e di Sweep, il mondo si ferma e la nostra applicazione Ruby si congela.
Con Ruby 1.8, ad intervalli prestabiliti vengono eseguite in sequenza le due fasi e questo determina un tangibile congelamento dell’applicazione a causa della durata combinata di queste due fasi.
Dalla versione 1.9.3 di Ruby la fase di Sweep anzichè essere eseguita subito dopo quella di Mark, viene suddivisa in microfasi che sono eseguite ogni volta che è richiesta l’allocazione di un nuovo oggetti. In questo modo il tempo necessario a svolgere la fase di Sweep “scompare” dalla nostra percezione, ma rimane quello necessario alla fase di Mark.
Con Ruby 2.0 è stato introdotta la Bitmap Marking GC.
Dietro questo curioso nome si nasconde una intelligente trovata di Narihiro Nakamura: tutti sapete cos’è l’ottimizzazione Copy On Write del sistema di gestione della memoria dei sistemi Linux e Unix based; i processi che vengono forkati (per esempio per gestire più richieste contemporaneamente in un server WEB) mantengono in comune oggetti in memoria fino al momento in cui uno dei processi va ad alterare l’oggetto. Questo consente di minimizzare l’utilizzo di memoria, ma nel momento in cui la fase di Mark altera il bit FL_MARK, questo fa venire meno la suddetta condizione e quindi l’ottimizzazione COW fallisce (limitatamente agli oggetti allocati dalla nostra applicazione Ruby). L’idea di Narihiro Nakamura è quella di spostare il bit FL_MARK in una sottostruttura (una bitmap) che diventa la sola parte che viene “sporcata” nella fase di Mark.
In Ruby 2.1 è stato introdotto un nuovo GC: questo è chiamato RGENGC (Restricted Generational GC), un GC generazionale parte dal presupposto che la maggior parte degli oggetti vengono allocati e poi “muoiono giovani”, il GC distingue tra oggetti “giovani” ed oggetti “vecchi”: gli oggetti “vecchi” sono quelli che “sopravvivono” all’n-esimo GC.
Con l’RGENGC vengono effettuati due distinti GC, il Minor GC in cui vengono trattati gli oggetti “giovani” e il Major GC (che viene eseguito solo quando la memoria scarseggia) in cui vengono trattati entrambi.
(segue)