2009-08-03 7 views
6

Capisco che in un linguaggio gestito come Java o C# c'è questa cosa chiamata garbage collector che ogni tanto controlla se ci sono qualsiasi istanza di oggetto che non è più referenziata, quindi completamente orfana, e quindi vuota dalla memoria. Ma se due oggetti non sono referenziati da alcuna variabile in un programma, ma si richiamano l'un l'altro (come una sottoscrizione ad un evento), il garbage collector vedrà questo riferimento e non cancellerà gli oggetti dalla memoria.Perché il garbage collector non può capire quando gli oggetti che fanno riferimento a eachother sono veramente orfani

Perché è questo? Perché il garbage collector non può capire che nessuno degli oggetti può fare riferimento a nessuna parte attiva del programma in esecuzione e smaltirli.

+5

In effetti, questo è uno dei problemi con gli ambienti di conteggio di riferimento che ** si occupa di ** nel .NET GC. –

+0

Ancora un'altra caratteristica Lisp tradizionale che si fa strada negli ambienti tradizionali. –

risposta

24

La presunzione non è corretta. Se il GC 'vede' (vedi sotto) un riferimento ciclico di 2 o più oggetti (durante la fase 'Mark') ma non sono referenziati da altri oggetti o maniglie GC permanenti (riferimenti forti), questi oggetti saranno raccolti (durante la fase 'Sweep').

Un'analisi approfondita del raccoglitore di rifiuti CLR è disponibile in this MSDN article e in this blog post.

Nota: In realtà, il GC non ha nemmeno 'vedere' questi tipi di oggetti durante la marchio fase dal momento che sono irraggiungibili, e quindi ottenere raccolti nel corso di una spazzare.

+0

Beh, ok, questo rende le cose molto più semplici. Quindi il mio programma ha una struttura ad albero composta da nodi, ognuno dei quali viene visualizzato tramite un TreeNode personalizzato in una vista ad albero. Se nulla fa riferimento al Node o al TreeNode, non devo preoccuparmi di staccare gli eventi o i riferimenti tra di essi. –

7

La maggior parte dei GC non funziona più con il conteggio dei riferimenti. Solitamente (e questo è il caso sia in Java che in .NET) funzionano con reach-ability dal set di root degli oggetti. Il set di oggetti radice è globale e istanze di riferimento di stack. Tutto ciò che è raggiungibile direttamente o indirettamente da quel set è vivo. Il resto della memoria è irraggiungibile e quindi soggetto a essere raccolto.

+0

In realtà, penso che sia sbagliato chiamare Reference-Conteggio una forma di Garbage-Collection. Sono 2 forme separate di gestione della memoria. –

+0

Il conteggio dei riferimenti (RC) è la forma della garbage collection (GC). L'algoritmo RC semplice non può gestire riferimenti ciclici, ma ci sono la tecnica di Bobrow, l'algoritmo del puntatore debole e gli algoritmi di mark-sweep parziali che possono. – mtasic85

2

Vorrei aggiungere che i problemi relativi all'abbonamento all'evento solitamente ruotano attorno al fatto che l'editore dell'abbonato & ha cicli di vita molto diversi.

Allegati per es. all'evento App.Idle in Windows Form e l'oggetto verrà mantenuto in vita per la durata rimanente dell'applicazione. Perché? Quella App statica manterrà un riferimento (anche se indirettamente tramite un delegato) all'osservatore registrato. Anche se potresti aver eliminato l'osservatore, è ancora collegato ad App.Idle. Puoi costruire molti di questi esempi.

1

Le altre risposte qui sono sicuramente corrette; .NET fa la garbage collection basata sulla raggiungibilità di un oggetto.

Quello che volevo aggiungere: posso consigliare di leggere Understanding Garbage Collection in .NET (articolo di Andrew Hunter con un semplice articolo) se volete informazioni più approfondite.

2

Questo è uno dei principali svantaggi del tradizionale reference counting garbage collection. La proprietà di un garbage collector che descrive questo comportamento è un raccoglitore incompleto. Altri collezionisti rientrano in gran parte in una categoria denominata tracciatori di immondizie, che comprendono gli ibridi tradizionali di marchiatura, semi-spazio/compattazione e generazionale e non soffrono di questi inconvenienti (ma ne affrontano molti altri).

Tutte le implementazioni di JVM e CLI Sono consapevole di uso collettori completi, il che significa che non soffrono il problema specifico che si sta chiedendo circa qui. A mia conoscenza, di quelli Jikes RVM è l'unico a fornire un collettore di conteggio di riferimento (uno dei suoi molti).

Un'altra cosa interessante da notare è che ci sono soluzioni al problema completezza in riferimento conteggio raccolta dei rifiuti, e l'resulting collectors dimostrano alcune proprietà interessanti prestazioni che sono difficili da ottenere su collettori tracciatura. Sfortunatamente, gli algoritmi di raccolta dei dati inutili con il conteggio delle prestazioni e le modifiche più complete dipendono dall'assistenza del compilatore, quindi portarli a C++ shared_ptr<T> è difficile/non sta accadendo. Invece, abbiamo weak_ptr<T> e documented rules (mi dispiace per il collegamento sub-ottimale - apparentemente la documentazione mi sfugge) semplicemente per evitare i problemi. Questo isn't the first time (altro link mediocre) che abbiamo visto questo approccio, e la speranza è il lavoro supplementare per evitare problemi di memoria è inferiore alla quantità di lavoro necessaria per mantenere il codice che non utilizza shared_ptr<T>, ecc

Il i collegamenti mediocri sono perché gran parte del mio materiale di riferimento è sparsa nelle note della classe di gestione della memoria dell'ultimo semestre.

Problemi correlati