Ragazzi, mi sembra che stiate facendo su un "rebelòtt"
La questione è molto più semplice:
- se A è un reference type (ovvero, è una classe, non una struct o un tipo primitivo), tutte le volte che dichiari una variabile di tipo A in realtà stai dichiarando un riferimento ad A; puoi pensare ad un riferimento come ad un "filo" che collega il nome della tua variabile all'oggetto (=istanza) vero e proprio;
- le istanze degli oggetti stanno nell'heap gestito; di base gli oggetti vengono costruiti (e la memoria viene allocata) solo quando c'è una "new"; se tu scrivi
stai facendo tre cose distinte e molto diverse:codice:A myA = new A();
- A myA dichiara un reference locale ad A, allocato sullo stack;
- new A() crea nell'heap un'istanza di A
- = fa puntare il riferimento myA all'oggetto appena creato sull'heap.
In generale, le variabili-riferimento e gli oggetti veri e propri allocati sull'heap non sono accoppiati in maniera stretta; se un riferimento esce di scope, oppure se crei un altro riferimento (=dichiari un'altra variabile) che punta allo stesso oggetto (A anotherA=myA;), all'oggetto vero e proprio non importa niente - lui sta lì per i fatti suoi sull'heap, dei riferimenti che puntano a lui non gliene frega niente.
Se tutta la questione terminasse così, ci sarebbe un serio problema: dato che l'uscita di scope dei reference non ha alcun effetto sugli oggetti sull'heap, dopo un po' l'heap si riempirebbe di spazzatura, ovvero di oggetti che non servono più, non essendo più raggiungibili tramite reference da parte del programma.
Qui entra in scena il garbage collector; quando il GC ne ha voglia, provvede ad esaminare tutto l'albero di riferimenti, segnandosi quali oggetti sono ancora raggiungibili da parte del programma (e quindi sono in uso); alla fine del procedimento, provvede ad eliminare quelli che non sono stati marcati, dato che sono tutta roba che non serve più (dato che il programma non vi può accedere tramite riferimenti, significa che è tutta roba non più usata).
In un certo senso, puoi vedere gli oggetti come dei palloncini e i riferimenti come dei fili; quando crei un nuovo oggetto, gonfi un palloncino, e assegnando il risultato della new ad una variabile ci leghi il suo filo; quando lo memorizzi in una collection, lo passi a funzioni, ... non stai facendo altro che legarci dei nuovi fili che passi ad altri pezzi del tuo codice. Ogni volta che un reference esce di scope (o ci viene assegnato null, oppure viene fatto puntare ad un altro oggetto), viene tagliato il suo filo (eventualmente ri-legandolo ad un altro oggetto se stai riassegnando il reference), e quando non c'è più nessun filo il palloncino vola via. Il GC non è altro che la "contraerea", che, per evitare che il cielo si riempia di palloncini vecchi, di tanto in tanto spara pallini e abbatte i palloncini senza fili.
Tornando quindi al tuo codice, anche l'hashtable in realtà è una hashtable di riferimenti; se rimuovi un elemento dalla hashtable, stai uccidendo un reference, e l'oggetto (palloncino) a cui puntava, se non ha altri riferimenti (fili), diventa passibile di garbage collection (contraerea). Quando tu rimpiazzi un elemento nella hashtable, quello che fai è:
- tagliare il filo al vecchio palloncino; se non ci sono altri palloncini, questo vola via, e tra un po' potrebbe essere abbattuto;
- gonfiare un nuovo palloncino (nel tuo caso più grosso);
- legare il nuovo palloncino allo stesso gancio a cui era attaccato il vecchio.
(in realtà anche la hashtable è un oggetto a cui c'è un riferimento come membro della classe, per cui in realtà sono palloncini legati ad altri palloncini che sono ancorati a terra mediante variabili sullo stack o variabili globali, ma la metafora inizia ad incasinarsi un po' troppo)
In tutto questo, come puoi vedere non viene espansa "memoria vecchia", ma piuttosto vengono rilasciati vecchi oggetti e allocati di nuovi. La chiave per evitare di sprecare memoria ovviamente è non mantenere riferimenti "di lunga durata" ad oggetti che non servono più - una volta rimosso un oggetto dalla hashtable, ad esempio, se hai altre variabili che puntano al "vecchio" oggetto può convenire impostarle a null (anche se va detto che la situazione non è così tragica come la dipingeva rsdpzed, di norma dei riferimenti locali ad una funzione è difficile che diano problemi, visto che spariscono appena escono di scope; quello che importa davvero sono riferimenti a livello di classe o memorizzati in altri oggetti).
---
Per inciso, dando un'occhiata al tuo codice mi sembra ci sia una certa confusione su static e compagnia - nello specifico, inizializzi variabili static dentro al costruttore d'istanzain linea di massima nella tua classe non credo ci dovrebbe essere alcunché di static.