2013-02-27 1 views

risposta

14

Contrariamente alla percezione comune, Finalize non causa la raccolta di dati da parte di un oggetto. Piuttosto, se si trova che non ha riferimenti radicati forti, un finalizzatore registrato sarà impedire l'oggetto da raccogliere immediatamente. Invece, l'oggetto verrà aggiunto a un elenco di oggetti fortemente radicato il cui metodo Finalize deve essere eseguito alla prima opportunità. Quando ciò accade, tutti i brevi riferimenti deboli all'oggetto verranno invalidati, ma i riferimenti deboli a lungo non lo saranno.

Se uno ha due o più oggetti che devono essere decostruiti in una particolare sequenza, può essere utile per quello che deve essere decostruito per ultimo avere un riferimento a quello che deve essere prima decostruito. Questa dovrebbe essere una qualche forma di riferimento debole, in modo che l'oggetto precedente non estenda inutilmente la durata dell'oggetto precedente, ma se fosse un riferimento debole e breve, diventerebbe inutilizzabile appena prima che fosse necessario. Rendendolo un riferimento lungo e debole evita questo problema.

Piuttosto più in generale, un breve riferimento debole è appropriato nei casi in cui si vuole solo conoscere un oggetto se è in uno stato utilizzabile, mentre una lunga riferimento debole è spesso opportuno nei casi in cui si ha la necessità di sapere su un oggetto indipendentemente dal suo stato. Come altro esempio, supponiamo che un server di database remoto possa solo interfacciarsi con un oggetto di connessione alla volta e che l'oggetto di connessione abbia un finalizzatore che notifica al server remoto che i suoi servizi non sono richiesti. Se un oggetto connessione viene abbandonato e viene effettuato un tentativo di ricollegare con quello stesso server, la gestione connessione deve essere in grado di trattare tre casi:

  • Ha un WeakReference che contiene un riferimento alla precedente oggetto di connessione, ed è ancora buono. In tal caso, il codice dovrebbe semplicemente iniziare a usarlo.

  • Il finalizzatore dell'oggetto connessione precedente è stato eseguito fino al completamento e il server remoto è pronto per una nuova connessione. In tal caso, il codice dovrebbe semplicemente creare un nuovo oggetto di connessione.

  • Il GC ha notato che l'oggetto di connessione è stato abbandonato e l'ha programmato per la finalizzazione, ma il finalizzatore non è ancora stato completato. In tal caso, il codice deve garantire che la vecchia connessione venga ripulita prima che possa essere stabilita una nuova.

Il primo caso può essere gestito tramite breve WeakReference. Determinare che la seconda o terza applicazione richiede un lungo WeakReference. Si noti che una volta che una connessione è stata accodata per la finalizzazione, il gestore delle connessioni non sarebbe interessato a provare a riutilizzarlo, ma dovrebbe comunque essere consapevole della sua esistenza.

+0

Grazie mille. Bella risposta. Risponde anche a un'altra domanda che ho avuto all'inizio della settimana. Ho fatto alcune domande a Stack Overflow ma questa risposta è una delle migliori o delle migliori che ho ricevuto. Grazie mille. –

+1

Nell'ipotetico scenario del gestore connessioni, come direi dal lungo WeakReference se l'oggetto è pianificato per la finalizzazione o meno (ad esempio, come posso dire al caso n. 1 a parte il caso n. 3)? Avrei solo un oggetto WeakReference con un target non nullo, ma come potrei dire in che stato era? –

+2

@MikeMarynowski: Un modo sarebbe utilizzare due riferimenti deboli, uno lungo e uno corto.Se quello corto è morto ma quello lungo è ancora valido, l'oggetto è stato programmato per il suo finalizzatore. – supercat