Introduzione
La gestione della memoria è il processo di allocare, deallocare e coordinare in modo efficiente la memoria in modo che tutti i diversi processi funzionino senza problemi e possano accedere in modo ottimale alle diverse risorse di sistema. La gestione della memoria comporta anche la pulizia della memoria degli oggetti che non sono più accessibili.
In Python, il gestore della memoria è responsabile di questo tipo di compiti eseguendo periodicamente per pulire, allocare e gestire la memoria. A differenza di C, Java e altri linguaggi di programmazione, Python gestisce gli oggetti usando il conteggio dei riferimenti. Questo significa che il gestore della memoria tiene traccia del numero di riferimenti ad ogni oggetto nel programma. Quando il conteggio dei riferimenti di un oggetto scende a zero, il che significa che l’oggetto non viene più usato, il garbage collector (parte del gestore della memoria) libera automaticamente la memoria da quel particolare oggetto.
L’utente non deve preoccuparsi della gestione della memoria poiché il processo di allocazione e de-allocazione della memoria è completamente automatico. La memoria recuperata può essere utilizzata da altri oggetti.
Python Garbage Collection
Come spiegato in precedenza, Python elimina gli oggetti che non sono più referenziati nel programma per liberare spazio di memoria. Questo processo in cui Python libera blocchi di memoria che non sono più utilizzati è chiamato Garbage Collection. Il Garbage Collector (GC) di Python viene eseguito durante l’esecuzione del programma e viene attivato se il numero di riferimenti si riduce a zero. Il conteggio dei riferimenti aumenta se ad un oggetto viene assegnato un nuovo nome o viene messo in un contenitore, come una tupla o un dizionario. Allo stesso modo, il conteggio dei riferimenti diminuisce quando il riferimento a un oggetto viene riassegnato, quando il riferimento dell’oggetto va fuori portata, o quando un oggetto viene cancellato.
La memoria è un heap che contiene oggetti e altre strutture dati utilizzate nel programma. L’allocazione e la de-allocazione di questo spazio heap è controllata dal gestore della memoria di Python attraverso l’uso di funzioni API.
Oggetti Python in memoria
Ogni variabile in Python si comporta come un oggetto. Gli oggetti possono essere semplici (contenenti numeri, stringhe, ecc.) o contenitori (dizionari, liste o classi definite dall’utente). Inoltre, Python è un linguaggio tipizzato dinamicamente, il che significa che non abbiamo bisogno di dichiarare le variabili o i loro tipi prima di usarle in un programma.
Per esempio:
Se guardate le prime 2 righe del programma sopra, l’oggetto x
è noto. Quando cancelliamo l’oggetto x
e cerchiamo di usarlo, otteniamo un errore che afferma che la variabile x
non è definita.
Si può vedere che la garbage collection in Python è completamente automatizzata e il programmatore non deve preoccuparsene, a differenza di linguaggi come il C.
Modificare il Garbage Collector
Il garbage collector Python ha tre generazioni in cui gli oggetti sono classificati. Un nuovo oggetto all’inizio del suo ciclo di vita è la prima generazione del garbage collector. Man mano che l’oggetto sopravvive alla garbage collection, viene spostato nelle generazioni successive. Ognuna delle 3 generazioni del garbage collector ha una soglia. In particolare, quando la soglia del numero di allocazioni meno il numero di de0allocazioni viene superata, quella generazione eseguirà la garbage collection.
Le generazioni precedenti vengono anche raccolte più spesso delle generazioni superiori. Questo perché gli oggetti più recenti hanno più probabilità di essere scartati rispetto a quelli vecchi.
Il modulo gc
include funzioni per cambiare il valore di soglia, avviare un processo di garbage collection manualmente, disabilitare il processo di garbage collection, ecc. Possiamo controllare i valori di soglia delle diverse generazioni del garbage collector usando il metodo get_threshold()
:
import gcprint(gc.get_threshold())
Sample Output:
(700, 10, 10)
Come vedete, qui abbiamo una soglia di 700 per la prima generazione, e 10 per ciascuna delle altre due generazioni.
Possiamo modificare il valore di soglia per l’attivazione del processo di garbage collection usando il metodo set_threshold()
del modulo gc
:
gc.set_threshold(900, 15, 15)
Nell’esempio precedente, abbiamo aumentato il valore di soglia per tutte e 3 le generazioni. L’aumento del valore di soglia diminuirà la frequenza di esecuzione del garbage collector. Normalmente, non abbiamo bisogno di pensare troppo alla garbage collection di Python come sviluppatori, ma questo può essere utile quando si ottimizza il runtime di Python per il sistema di destinazione. Uno dei vantaggi principali è che il meccanismo di garbage collection di Python gestisce automaticamente molti dettagli di basso livello per lo sviluppatore.
Perché eseguire la garbage collection manuale?
Sappiamo che l’interprete Python tiene traccia dei riferimenti agli oggetti usati in un programma. Nelle versioni precedenti di Python (fino alla versione 1.6), l’interprete Python usava solo il meccanismo di conteggio dei riferimenti per gestire la memoria. Quando il conteggio dei riferimenti scende a zero, l’interprete Python libera automaticamente la memoria. Questo classico meccanismo di conteggio dei riferimenti è molto efficace, tranne per il fatto che non funziona quando il programma ha dei cicli di riferimento. Un ciclo di riferimento si verifica se uno o più oggetti sono referenziati l’un l’altro, e quindi il conteggio di riferimento non raggiunge mai lo zero.
Consideriamo un esempio.
>>> def create_cycle():... list = ... list.append(list)... return list... >>> create_cycle()]
Il codice sopra crea un ciclo di riferimento, dove l’oggetto list
fa riferimento a se stesso. Quindi, la memoria dell’oggetto list
non sarà liberata automaticamente quando la funzione ritorna. Il problema del ciclo di riferimento non può essere risolto dal conteggio dei riferimenti. Tuttavia, questo problema del ciclo di riferimento può essere risolto cambiando il comportamento del garbage collector nella vostra applicazione Python.
Per farlo, possiamo usare la funzione gc.collect()
del modulo gc
.
import gcn = gc.collect()print("Number of unreachable objects collected by GC:", n)
La gc.collect()
restituisce il numero di oggetti che ha raccolto e deallocato.
Ci sono due modi per eseguire la garbage collection manuale: la garbage collection basata sul tempo o quella basata sugli eventi.
La garbage collection basata sul tempo è abbastanza semplice: la funzione gc.collect()
viene chiamata dopo un intervallo di tempo fisso.
La garbage collection basata sugli eventi chiama la funzione gc.collect()
dopo che si è verificato un evento (cioè quando l’applicazione è uscita o l’applicazione rimane inattiva per un determinato periodo di tempo).
Comprendiamo il lavoro della garbage collection manuale creando alcuni cicli di riferimento.
L’output è il seguente:
Creating garbage...Collecting...Number of unreachable objects collected by GC: 8Uncollectable garbage:
Lo script sopra crea un oggetto lista che è riferito da una variabile, creativamente chiamata list
. Il primo elemento dell’oggetto lista si riferisce a se stesso. Il conteggio dei riferimenti dell’oggetto lista è sempre maggiore di zero anche se è cancellato o fuori portata nel programma. Quindi, l’oggetto list
non viene raccolto a causa del riferimento circolare. Il meccanismo di garbage collector in Python controllerà automaticamente e raccoglierà periodicamente i riferimenti circolari.
Nel codice sopra, poiché il conteggio dei riferimenti è almeno 1 e non può mai raggiungere lo 0, abbiamo forzato il garbage collect degli oggetti chiamando gc.collect()
. Tuttavia, ricordatevi di non forzare la garbage collection frequentemente. La ragione è che anche dopo aver liberato la memoria, il GC impiega del tempo per valutare l’idoneità dell’oggetto ad essere garbage collect, occupando tempo e risorse del processore. Inoltre, ricordatevi di gestire manualmente il garbage collector solo dopo che la vostra applicazione si è avviata completamente.
Conclusione
In questo articolo, abbiamo discusso come la gestione della memoria in Python è gestita automaticamente utilizzando strategie di conteggio dei riferimenti e garbage collection. Senza garbage collection, implementare un meccanismo di gestione della memoria di successo in Python è impossibile. Inoltre, i programmatori non devono preoccuparsi di cancellare la memoria allocata, in quanto se ne occupa il gestore della memoria di Python. Questo porta a meno perdite di memoria e a migliori prestazioni.