la tua situazione è quella in cui hai due riferimenti ad un oggetto e ne disponi l'eliminazione attraverso uno dei due. L'oggetto non puo essere eliminato e non per via della GC ma perchè è ancora perfettamente lecito usarlo attraverso l'altro riferimento.
Riducendo all'osso tu hai una cosa del genere:
Dopo il Solve puoi ancora utilizzare il pianeta attraverso la o. Non è stato eliminato e non lo sarà finche il riferimento o non perderà lo scope.codice:class My { collection Planets; void H1(string key) { planet o = Planets[key]; Solve(key); //o esiste o è stato eliminato? } void Solve(string key) { Planets.Remove(key); } }
Ecco cosa accade (mooolto teoricamente):
1) Crei la collection di pianeti a livello di classe e fai partire il main (o il ciclo Update Draw nel tuo caso). Nello stack viene memorizzato un riferimento alla collection (Planets) e in memoria vengono istanziati, diciamo, 3 pianeti.
2) Entri in H1 e nello stack memorizzi un ulteriore riferimento ad uno dei tre pianeti, diciamo il secondo. In questo momento il secondo pianeta è raggiungibile sia da questo riferimento sia dal riferimento all'intera collection.
2a) Il Garbage collector ha bisogno di memoria e inizia ad analizzare lo stack. Trova Planets che punta ai tre pianeti in memoria e contrassegna quei tre pianeti come oggetti da non eliminare, poi trova o che punta al secondo pianeta e lo contrassegna come da non eliminare (inutile visto che l'ha fatto prima). Il GC ora comincia a scorrere la memoria per eliminare tutti gli oggetti non marcati ma non elimina nulla.
3) Entri in Solve e viene comandata l'eliminazione del secondo pianeta. Planets ora punta ad una collection fatta di due pianeti il primo e il terzo mentre o punta al secondo pianeta.
3a) Il GC necessita di memoria e ricomincia ad analizzare lo stack. Planets punta al primo e al terzo e i due pianeti vengono contrassegnati come oggetti da non eliminare. o punta al secondo e anche lui viene graziato. Ancora una volta scorrendo la memoria il GC non trova nulla da eliminare.
4) Termina lo scope di Solve e si ritorna in H1. I pianeti sono intatti solo che attraverso la collection non puoi piu vedere il secondo pianeta che puoi comunque raggiungere attraverso il riferimento o.
5) Termina H1 e quindi termina anche lo scope di 'o' il quale viene eliminato dallo stack.
5a) Il GC ha bisogno di memoria e comincia ad analizzare lo stack. Trova Planets che punta al primo e al terzo e marca i due oggetti per non eliminarli. Non trova nientaltro nello stack. Ora va in memoria e comincia ad eliminare tutti gli oggetti che non sono stati marcati, trova il secondo pianeta e lo elimina.
Questo fatto di tenere in vita un riferimento ad un oggetto che andrebbe eliminato, lungo una catena di chiamate è da evitare il piu possibile. Prima che per le performance la ragione principale è la consistenza dello stato del programma: Cosa ci fa in giro un pianeta nello stato di Near se il programma lo ha messo in stato di Far? Magari nel tuo caso non succede nulla ma in linea generale è (o sarà) un problema.
Dal lato performance la cosa sicuramente crea delle ripercussioni. Se dopo il solve o l'unsolve hai bisogno di memoria, perche magari devi mettere in Near altri tot pianeti, non potrai contare su quella che si sarebbe liberata dai pianeti near contrassegnati come Far fino alla fine di H1 e cioè al prossimo giro.
Quello che segue potrebbe stravolgere quanto detto fin'ora e per questo lo metto solo alla fine...
E se il tipo shipworld è una struct e non un oggetto? (cosa che in xna accade poco è spesso).
Qui le cose cambiano.
Le struct non sono oggetti in memoria e non hanno riferimenti. le struct vengono copiate nello stack cosi come sono e vengono eliminate al termine dello scope.
Le collection sono oggetti in memoria per cui Planets rimane cosi com'è (un array di pianeti in memoria anche se i pianeti sono struct), quello che cambia è la variabile o. o non è piu un riferimento al secondo pianeta memoria. o è una variabile nello stack dentro cui viene copiato tutto il contenuto del secondo pianeta.
Nel punto 3a della timeline precedente il secondo pianeta viene eliminato perche 'o' non lo referenzia e quindi il GC non lo ha marcato per la 'sopravvivenza'.
Questo risolverebbe il problema delle performance ma non risolve il primo e piu importante problema: che ci fa un o ancora in giro?
Tutta questa pappina per arrivare alla conclusione:
Evita questa situazione il piu possibile. quando devi modificare una collection usa la collection e non riferimenti agli oggetti dentro la collection. I riferimenti agli oggetti della collection andrebbero usati solo quando la collection non viene modificata magari quando un oggetto viene passato ad una funzione che non vede la collection intera (e quindi non puo modificaarla). In tutti gli altri casi usa direttamente il riferimento alla collection (planets[key]).