Domanda

L'uso di riferimenti deboli è qualcosa di cui non ho mai visto un'implementazione, quindi sto cercando di capire quale sia il caso d'uso per loro e come funzionerebbe l'implementazione. Quando è necessario utilizzare un WeakHashMap o WeakReference e come è stato utilizzato?

È stato utile?

Soluzione

  

Un problema con riferimenti forti è   memorizzazione nella cache, in particolare con dimensioni molto grandi   strutture come immagini. Supponiamo che tu   avere un'applicazione che deve funzionare   con immagini fornite dall'utente, come il   strumento di progettazione di siti Web su cui lavoro.   Naturalmente vuoi memorizzarli nella cache   immagini, perché caricandole dal disco   è molto costoso e tu lo vuoi   evitare la possibilità di averne due   copie del (potenzialmente gigantesco)   immagine in memoria contemporaneamente.

     

Perché dovrebbe essere una cache di immagini   impedirci di ricaricare le immagini quando   non ne abbiamo assolutamente bisogno, lo farai   rendersi conto rapidamente che la cache dovrebbe   contiene sempre un riferimento a qualsiasi   immagine che è già in memoria. Con   ordinari riferimenti forti, tuttavia,   quel riferimento stesso forzerà il   immagine per rimanere in memoria, che   richiede in qualche modo di determinare quando   l'immagine non è più necessaria in   memoria e rimuoverlo dalla cache,   in modo che diventi idoneo per   raccolta dei rifiuti. Sei costretto a farlo   duplicare il comportamento della spazzatura   collezionista e determinare manualmente   se un oggetto dovrebbe essere presente o meno   la memoria.

Comprensione di riferimenti deboli , Ethan Nicholas

Altri suggerimenti

Una distinzione da chiarire è la differenza tra un WeakReference e un SoftReference .

Fondamentalmente un WeakReference sarà GC-d dalla JVM avidamente, una volta che l'oggetto referenziato non ha hard riferimenti ad esso. D'altra parte, un oggetto SoftReference tenderà a essere lasciato in giro dal garbage collector fino a quando non avrà davvero bisogno di recuperare la memoria.

Una cache in cui i valori sono contenuti all'interno di WeakReference sarebbe piuttosto inutile (in un WeakHashMap , sono le chiavi che sono debolmente si fa riferimento). SoftReferences sono utili per racchiudere i valori quando si desidera implementare una cache che può crescere e ridursi con la memoria disponibile

Un uso comune di WeakReference e WeakHashMap in particolare è per l'aggiunta di proprietà agli oggetti. Occasionalmente vuoi aggiungere alcune funzionalità o dati a un oggetto ma la sottoclasse e / o la composizione non sono un'opzione in quel caso la cosa ovvia da fare sarebbe creare una hashmap che collega l'oggetto che vuoi estendere alla proprietà che vuoi aggiungere . quindi ogni volta che hai bisogno della proprietà puoi semplicemente cercarla nella mappa. Tuttavia, se gli oggetti che stai aggiungendo tendono a essere distrutti e creati molto, puoi finire con un sacco di vecchi oggetti nella tua mappa che occupano molta memoria.

Se usi un WeakHashMap invece gli oggetti lasceranno la tua mappa non appena non saranno più utilizzati dal resto del tuo programma, che è il comportamento desiderato.

Ho dovuto fare questo per aggiungere alcuni dati a java.awt.Component per aggirare un cambiamento nel JRE tra 1.4.2 e 1.5, avrei potuto risolverlo sottoclassando ogni componente I era interessato a int ( JButton , JFrame , JPanel ....) ma era molto più facile con molto meno codice.

Un altro caso utile per WeakHashMap e WeakReference è una implementazione del registro dell'ascoltatore .

Quando crei qualcosa che vuole ascoltare determinati eventi, di solito registri un ascoltatore, ad esempio

manager.registerListener(myListenerImpl);

Se il manager memorizza il tuo ascoltatore con un WeakReference , ciò significa che non è necessario rimuovere il registro, ad es. con un manager.removeListener (myListenerImpl) perché verrà automaticamente rimosso una volta che il listener o il componente che lo detiene diventa non disponibile.

Ovviamente puoi ancora rimuovere manualmente il tuo ascoltatore, ma se non lo fai o lo dimentichi, non causerà una perdita di memoria e non impedirà che il tuo ascoltatore venga raccolto.

Dove compare WeakHashMap ?

Il registro degli ascoltatori che desidera archiviare gli ascoltatori registrati come WeakReference ha bisogno di una raccolta per memorizzare questi riferimenti. Non esiste un'implementazione WeakHashSet nella libreria Java standard solo un WeakHashMap ma possiamo facilmente usare quest'ultima per " implementare " la funzionalità del primo:

Set<ListenerType> listenerSet =
    Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());

Con questo listenerSet per registrare un nuovo listener devi solo aggiungerlo al set, e anche se non viene rimosso esplicitamente, se al listener non viene più fatto riferimento, verrà rimosso automaticamente dalla JVM.

Questo post sul blog dimostra l'uso di entrambe le classi: Java: sincronizzazione su un ID . L'utilizzo è simile al seguente:

private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider();

public void performTask(String resourceId) {
    IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId);
    synchronized (mutext) {
        // look up the resource and do something with it
    }
}

IdMutextProvider fornisce oggetti basati su ID per la sincronizzazione. I requisiti sono:

  • deve restituire un riferimento allo stesso oggetto per l'uso simultaneo di ID equivalenti
  • deve restituire un oggetto diverso per ID diversi
  • nessun meccanismo di rilascio (gli oggetti non vengono restituiti al provider)
  • non deve perdere (gli oggetti non utilizzati sono idonei per la garbage collection)

Questo si ottiene utilizzando una mappa di archiviazione interna di tipo:

WeakHashMap<Mutex, WeakReference<Mutex>>

L'oggetto è sia chiave che valore. Quando nulla di esterno alla mappa ha un forte riferimento all'oggetto, può essere spazzato via. I valori nella mappa sono memorizzati con riferimenti concreti, quindi il valore deve essere racchiuso in un WeakReference per evitare una perdita di memoria. Quest'ultimo punto è trattato nel javadoc .

Se ad esempio vuoi tenere traccia di tutti gli oggetti creati di una determinata classe. Per consentire comunque la raccolta differenziata di questi oggetti, è necessario mantenere un elenco / una mappa di riferimenti deboli agli oggetti anziché agli oggetti stessi.

Ora, se qualcuno potesse spiegarmi riferimenti fantasma, sarei felice ...

Come indicato sopra, i riferimenti deboli vengono mantenuti finché esiste un riferimento forte.

Un esempio potrebbe essere l'uso di WeakReference all'interno dei listener, in modo che i listener non siano più attivi una volta sparito il riferimento principale al loro oggetto target. Si noti che ciò non significa che WeakReference venga rimosso dall'elenco dei listener, è comunque necessario ripulire ma può essere eseguito, ad esempio, in orari programmati. Questo ha anche l'effetto di impedire all'oggetto ascoltato di contenere riferimenti forti e alla fine essere una fonte di memoria gonfia. Esempio: componenti della GUI di Swing che fanno riferimento a un modello con un ciclo di vita più lungo rispetto alla finestra.

Mentre suonavamo con gli ascoltatori come descritto sopra, ci siamo rapidamente resi conto che gli oggetti venivano raccolti "immediatamente". dal punto di vista di un utente.

Un uso reale che ho avuto per WeakReferences è se hai un singolo oggetto molto grande che viene usato raramente. Non vuoi tenerlo in memoria quando non è necessario; ma, se un altro thread ha bisogno dello stesso oggetto, non ne vuoi nemmeno due in memoria. È possibile mantenere un riferimento debole all'oggetto da qualche parte e riferimenti duri nei metodi che lo utilizzano; quando entrambi i metodi finiscono, l'oggetto verrà raccolto.

Ho fatto una ricerca nel codice di Google per " new WeakHashMap () " ;.

Ho ricevuto un sacco di partite dal progetto GNU classpath e

  1. Progetto Apache xbean: WeakHashMapEditor.java
  2. Progetto Apache Lucene: CachingWrapperFilter.java

puoi usare weakhashmap per implementare una cache senza risorse per la creazione di oggetti espansivi.

ma nota che non è desiderabile avere oggetti mutabili. l'ho usato per memorizzare nella cache i risultati delle query (che richiedono circa 400 ms per l'esecuzione) su un motore di ricerca di testo, che viene aggiornato raramente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top