2009-04-23 10 views
16

Mi chiedo come i riferimenti deboli funzionino internamente, ad esempio in .NET o in Java. Le mie due idee generali sono:Come vengono implementati i riferimenti deboli?

  1. "Intrusive" - ​​per aggiungere un elenco di riferimenti deboli alla classe più alta (classe oggetto). Quindi, quando un oggetto viene distrutto, tutti i riferimenti deboli possono essere iterati e impostati su null.
  2. "Non intrusivo" - per mantenere un hash dei puntatori di oggetti alle liste di riferimenti deboli. Quando un riferimento debole A viene creato su un oggetto B, ci sarà una voce nella tabella hash modificata o creata, la cui chiave sarebbe il puntatore a B.
  3. "Sporco" - per memorizzare un valore hash speciale con ciascun oggetto , che verrebbe azzerato quando l'oggetto viene distrutto. I riferimenti deboli dovrebbero copiare quel valore di hash e confrontarlo con il valore dell'oggetto per verificare se l'oggetto è vivo. Ciò, tuttavia, causerebbe errori di violazione di accesso, se usato direttamente, quindi ci sarebbe bisogno di essere un oggetto aggiuntivo con quel valore hash, penso.

Una di queste soluzioni sembra pulita ed efficiente. Qualcuno sa come viene effettivamente fatto?

risposta

5

Non sono sicuro di aver capito la tua domanda, ma puoi dare un'occhiata all'implementazione per la classe WeakReference e la sua superclasse Reference in Java. È ben commentato e si può vedere che ha un campo trattato appositamente dal GC e un altro usato direttamente dalla VM.

+0

Trovato: http://java.sun.com/j2se/1.5.0/source_license.html –

+0

Novità qui: http://download.java.net/openjdk/jdk7/ –

6

In .NET, quando viene creato uno WeakReference, al GC viene richiesto un token handle/opaco che rappresenta il riferimento. Quindi, quando necessario, WeakReference utilizza questo handle per chiedere al GC se tale handle è ancora valido (ovvero l'oggetto originale esiste ancora) e, in tal caso, può ottenere il riferimento all'oggetto effettivo.

Quindi questa è la costruzione di una lista di token/maniglie contro gli indirizzi degli oggetti (e il mantenimento di tale elenco, presumibilmente durante la deframmentazione, ecc)

io non sono sicuro al 100% ho capito i tre proiettili, così ho esitato a indovinare quale (se presente) che è più vicino a

+0

Un potenziale problema è determinare se il token fa riferimento all'oggetto originale oa un nuovo oggetto che si trova ad occupare la stessa posizione nella memoria. Penso che le implementazioni esistenti utilizzino una callback che invalida il riferimento debole quando l'oggetto è finalizzato. –

+2

Un GC di compattazione deve comunque avere una soluzione per questo problema, poiché sposta gli oggetti sempre. –

2

Python's PEP 205 ha una spiegazione decente di come i riferimenti deboli dovrebbero comportarsi in Python e questo fornisce alcune informazioni su come possono essere implementati. Dato che un riferimento debole è immutabile, si potrebbe avere solo uno per ciascun oggetto, al quale si passano i riferimenti secondo necessità. Pertanto, quando l'oggetto viene distrutto, solo un riferimento debole deve essere invalidato.

0

L'approccio normale, penso, è che il sistema mantenga una sorta di elenco di riferimenti deboli. Quando il garbage collector viene eseguito, prima che gli oggetti morti vengano rimossi, il sistema itera attraverso l'elenco di riferimenti deboli e invalida qualsiasi riferimento il cui target non sia stato taggato dal vivo. A seconda del sistema, questo può verificarsi prima o dopo che il sistema resuscita temporaneamente gli oggetti che sono idonei per la finalizzazione immediata (nel caso di .net, esistono due tipi di WeakReference - uno dei quali viene elaborato in modo efficace prima che il sistema esegua la scansione dei finalizzatori , il che significa che diventerà non valido quando il suo target diventa idoneo per la finalizzazione e uno dei quali viene elaborato dopo).

Per inciso, se fossi la progettazione di un quadro gc-based, vorrei aggiungere un paio di altre cose: (1) un mezzo di dichiarare un riferimento di tipo posizione archiviazione come in possesso di un riferimento che è in primo luogo interessare a qualcuno else, and (2) Una varietà di WeakReference che potrebbe indicare che gli unici riferimenti a un oggetto sono in posizioni di memoria "di interesse per qualcun altro".Anche se WeakReference è un tipo utile, l'atto di trasformare un riferimento debole in un riferimento forte può impedire al sistema di riconoscere che a nessuno sarebbe dispiaciuto se il suo obiettivo scomparisse.

2

Sembra che l'implementazione di riferimenti deboli sia ben tenuta segreta nel settore ;-). Ad esempio, a partire da ora, wikipedia article manca di dettagli sull'implementazione. E guarda le risposte sopra (compresa quella accettata): "guarda la fonte" o "Penso"; - \.

Di tutte le risposte, solo quella che fa riferimento a PEP 205 di Python è perspicace. Come dice, per ogni singolo oggetto, ci può essere al massimo un riferimento debole, se trattiamo weakref come un'entità stessa.

Il resto descrive l'implementazione del linguaggio Squirrel. Quindi, weakref è esso stesso un oggetto, quando metti un riferimento debole ad un oggetto in un contenitore, in realtà metti il ​​riferimento all'oggetto weakref. Ogni oggetto con riferimento numerabile ha un campo per memorizzare il puntatore sul suo weakref, che è NULL finché non viene effettivamente richiesto weakref a quell'oggetto. Ogni oggetto ha il metodo per richiedere weakref, che restituisce dal campo il suffisso esistente (singleton), oppure lo crea e le memorizza nel campo.

Ovviamente, punti weakref per l'oggetto originale. Quindi, devi solo passare attraverso tutti i posti disponibili dove vengono gestiti i riferimenti agli oggetti e aggiungere una gestione trasparente di weakrefs (cioè dereferenziarla automaticamente). (Alternativa "trasparente" consiste nell'aggiungere il metodo di "accesso" virtuale che sarà l'identità per la maggior parte degli oggetti e il dereferenziamento effettivo per weakref.)

E come oggetto ha puntatore al suo weakref, quindi l'oggetto può NULLificare il weakref in proprio distruttore.

Questa implementazione è abbastanza pulita (nessuna magia "chiama in GC" e altro) e ha un costo di runtime O (1). Certo, è piuttosto avido di memoria - è necessario aggiungere un campo puntatore +1 a ciascun oggetto, anche se in genere per 90 +% oggetti che sarebbero NULL. Naturalmente, i VHLL hanno già un sovraccarico di memoria di grandi dimensioni per oggetto, e potrebbe esserci la possibilità di compattare diversi campi "extra". Ad esempio, il tipo di oggetto è in genere una piccola enumerazione, quindi potrebbe essere possibile unire il tipo e un qualche tipo di riferimento weakref in una singola parola macchina (ad esempio, mantenere gli oggetti weakref in un'arena separata e utilizzare l'indice).