Dangling pointers

A grande richiesta del pubblico, un applauso per il ritorno dei 🎸 dangling pointeeeeeeeers!!!! 🎸

Ti è mai capitato di allocare blocchi di memoria puntati da un bel puntatore, magari copiare il valore di quel puntatore in altre parti del programma, e poi deallocare il blocco senza eliminare il riferimento dei puntatori?

Se la risposta è no stai chiaramente mentendo.

Questi puntatori che indicano celle di memoria ormai deallocate sono detti dangling pointers (puntatori penzolanti per le bestie di satana) e il loro utilizzo può portare a comportamenti imprevedibili.

Tombstones

Un modo per gestire il problema è l’utilizzo delle cosiddette tombstones.

In pratica nel momento in cui si alloca della memoria il riferimento lo si salva in una tombstone e poi tutti gli altri puntatori fanno fede ad essa, creando quindi un meccanismo di doppio salto. Nel momento in cui la memoria viene deallocata la tombstone impedisce agli altri puntatori di accedere alla porzione di memoria liberata sollevando un errore ad ogni tentativo di accesso.

Per quanto efficace, questo meccanismo raddoppia i puntatori necessari per un riferimento e occupa porzioni di memoria che non potremo mai più reclamare fino al termine dell’esecuzione (quelle occupate dai tombstone).

Locks and keys

Un’alternativa alle tombstones è il locks and keys, ma solo per i puntatori all’heap.

Ogni volta che si alloca un oggetto nell’heap, esso viene associato con un “lock” costituito da una word di memoria che contiene un valore casuale, a questo punto un puntatore sarà formato da due parti: l’indirizzo e una “key”, ovvero una word di memoria inizializzata al valore del lock dell’oggetto puntato.

Ogni volta che viene dereferenziato l’oggetto puntato, si controlla che key e lock combacino. Quando l’oggetto viene deallocato il lock viene impostato ad un valore canonico e così facendo invalida ogni possibile dereferenziazione successiva.

Anche locks and keys ha un costo non indifferente sia in termini spaziali (costa anche piĂą delle tombstone, dato che richiede una word di memoria in piĂą per ogni puntatore), sia in termini di efficienza, in quando appesantiscono tutte le operazioni.

Garbage collectors

Nei linguaggi sprovvisti di una deallocazione esplicita della memoria sull’heap, il meccanismo che gestisce la deallocazione degli oggetti non più usati è il garbage collector (comparso per la prima volta in lisp ma ormai presente in molti linguaggi di successo come javascript, python e java).

Le operazioni eseguite dal garbage collector sono due:

  1. Garbage detection: ovvero l’individuazione degli oggetti presenti in memoria ma non più usati;
  2. Garbage collection: ovvero la liberazione della memoria usata da questi oggetti.