martedì 24 febbraio 2026

Corso di Programmazione Strutturata e OOP: 5 Gestione della memoria

 


💾 5 Gestione della Memoria

Quando programmiamo, ogni dato che utilizziamo – numeri, stringhe, immagini, strutture complesse – deve essere memorizzato in uno spazio fisico: la memoria RAM. Comprendere come questa viene organizzata e gestita significa entrare nel livello strutturale dell’informatica, dove efficienza, velocità e stabilità del software dipendono da scelte progettuali consapevoli.

La gestione della memoria non è solo un dettaglio tecnico: è uno degli elementi che distingue un codice “che funziona” da un codice robusto, scalabile e performante.

📌 Cos'è la memoria in un programma

La memoria è uno spazio indirizzabile composto da celle numerate (indirizzi). Ogni cella può contenere una quantità limitata di dati. Quando scriviamo:

x = 5

accadono diverse operazioni invisibili:

  1. Viene creato un oggetto intero con valore 5.
  2. Questo oggetto viene allocato in memoria.
  3. Il nome x diventa un riferimento a quell’oggetto.

È importante comprendere che in Python le variabili non contengono direttamente il valore, ma un riferimento a un oggetto memorizzato altrove.

Stack e Heap (concetto generale)

In molti linguaggi la memoria si divide concettualmente in:

  • Stack → memoria veloce, organizzata in modo strutturato (variabili locali, chiamate di funzione).
  • Heap → memoria dinamica, usata per oggetti creati durante l’esecuzione.

Python gestisce automaticamente queste aree, ma internamente utilizza meccanismi simili.

📦 Variabili, strutture dati e spazio occupato

🔹 Variabili semplici

Un intero (int) o un booleano occupano meno memoria rispetto a strutture complesse, ma in Python anche gli interi sono oggetti, quindi hanno un overhead interno (metadati, gestione del tipo, contatore di riferimenti).

Esempio:

a = 10
b = 10

In Python, piccoli interi possono essere condivisi (ottimizzazione interna), quindi a e b possono riferirsi allo stesso oggetto in memoria.

🔹 Liste

Una lista non contiene direttamente i valori, ma riferimenti agli oggetti.

lista = [1, 2, 3]

In memoria abbiamo:

  • L’oggetto lista
  • Tre oggetti intero
  • Tre riferimenti nella lista

Questo significa che una lista cresce in modo dinamico e può richiedere riallocazioni di memoria quando aumenta di dimensione.

🔹 Dizionari

I dizionari utilizzano tabelle hash. Ogni elemento richiede:

  • Chiave
  • Valore
  • Calcolo hash
  • Struttura di gestione collisioni

Sono estremamente veloci nelle ricerche, ma consumano più memoria rispetto a una lista equivalente.

🔹 Array vs Liste

Strutture come gli array (ad esempio tramite librerie scientifiche) sono più efficienti perché memorizzano dati omogenei in modo contiguo, riducendo overhead e migliorando la località di memoria.

📏 Cosa significa “occupare spazio”?

Ogni oggetto occupa:

  • Spazio per il valore
  • Spazio per il tipo
  • Spazio per il contatore di riferimenti
  • Eventuale spazio per strutture interne

Un programma è “pesante” quando:

  • Crea troppi oggetti inutili
  • Duplica dati invece di riutilizzarli
  • Mantiene riferimenti non necessari
  • Usa strutture complesse quando non servono

Esempio inefficiente:

numeri = []
for i in range(1000000):
    numeri.append(i)

Se i dati non servono tutti contemporaneamente, una soluzione più efficiente potrebbe essere usare un generatore, che non carica tutto in memoria.

🧹 Garbage Collection in Python

Python utilizza due meccanismi principali:

1️⃣ Reference Counting

Ogni oggetto ha un contatore di riferimenti. Quando il contatore scende a zero, l’oggetto viene eliminato.

a = [1, 2, 3]
b = a
del a

L’oggetto non viene eliminato finché b esiste.

2️⃣ Garbage Collector Ciclico

Gestisce i riferimenti circolari, cioè oggetti che si riferiscono tra loro impedendo al contatore di scendere a zero.

Esempio concettuale:

a = []
b = []
a.append(b)
b.append(a)

Qui i due oggetti si referenziano reciprocamente.

Python interviene periodicamente per liberare memoria in questi casi.

⚠ Tuttavia, il Garbage Collector non è una soluzione magica: mantenere oggetti inutilizzati rallenta comunque il sistema.

⚠️ Errori comuni

❌ Variabili non inizializzate

Provocano errori di runtime e indicano cattiva gestione dello stato del programma.

❌ Sovrascrittura involontaria

lista = [1,2,3]
lista = 5

Il nome cambia significato, generando potenziali bug logici.

❌ Copie inutili

nuova_lista = lista[:]

Se non necessario, questa operazione raddoppia l’uso di memoria.

❌ Memory leak logici

In Python non sono comuni come in C/C++, ma possono verificarsi quando oggetti restano referenziati senza necessità.

🚀 Strategie per scrivere codice più efficiente

  • Usare generatori (yield) per grandi sequenze
  • Eliminare variabili inutilizzate (del)
  • Riutilizzare strutture dati quando possibile
  • Scegliere la struttura dati più adatta
  • Evitare copie profonde non necessarie
  • Profilare la memoria con strumenti dedicati

🔬 Attività pratiche approfondite

🔎 1. Visualizzazione della memoria

Utilizzare strumenti didattici come:

  • pythontutor.com

Osservare:

  • Creazione oggetti
  • Riferimenti
  • Eliminazione variabili

Obiettivo: sviluppare consapevolezza visiva dei meccanismi interni.

📊 2. Analisi comparata

Confrontare:

Versione inefficiente

lista = [i for i in range(1000000)]
somma = sum(lista)

Versione ottimizzata

somma = sum(i for i in range(1000000))

Misurare:

  • Tempo di esecuzione
  • Consumo di memoria

🧪 3. Laboratorio guidato

Progetto: analizzatore di dati numerici

Obiettivo:

  • Leggere numeri
  • Calcolare media
  • Non conservare dati inutili

Soluzione efficiente:

  • Elaborazione progressiva
  • Uso minimo di memoria
  • Nessuna lista intermedia

🎯 Conclusione

La gestione della memoria è il punto di incontro tra teoria dell’informazione, architettura dei calcolatori e qualità del software.

Comprendere:

  • Come vengono allocati gli oggetti
  • Come funzionano i riferimenti
  • Quando la memoria viene liberata
  • Come scegliere le strutture dati

significa scrivere programmi più veloci, più puliti e più professionali.

Un buon programmatore non pensa solo a “far funzionare” il codice: pensa a come occupa lo spazio, quanto consuma e quanto può scalare nel tempo.

🧪 Verifica le tue conoscenze

1. Cosa fa la garbage collection in Python?

2. Cosa succede se usi una variabile non inizializzata?

3. Quale delle seguenti strutture occupa in genere più memoria?

Punteggio: 0/3

Nessun commento:

Posta un commento

Corso di CSS & Web Design: 9 – Progetto completo di un sito internet

9 – Progetto completo di un sito internet  Struttura dettagliata del sito di un artista di arti figurative 🎯 Obiettivi del sito Presentar...