2013-10-24 10 views
12

Ho una mappa che uso per memorizzare dati dinamici che vengono scartati non appena vengono creati (cioè utilizzati, vengono consumati rapidamente). Risponde all'interazione dell'utente nel senso che quando l'utente fa clic su un pulsante, la mappa viene riempita e quindi i dati vengono utilizzati per fare un po 'di lavoro e quindi la mappa non è più necessaria.Map clear vs null

Quindi la mia domanda è quale approccio migliore per lo svuotamento della mappa? dovrei impostarlo su null ogni volta o dovrei chiamare clear()? So che la chiarezza è lineare nel tempo. Ma non so come confrontare questo costo con quello di creare ogni volta la mappa. La dimensione della mappa non è costante, pensavo che potesse essere eseguita da n a 3n elementi tra le creazioni.

risposta

7

Se una mappa non è referenziato da altri oggetti in cui può essere difficile impostare una nuova, semplicemente null -ing fuori una vecchia mappa e partendo da zero è probabilmente più leggero che chiamare un clear(), perché nessun mondo attuatori la pulizia del tempo deve accadere. Con la riduzione dei costi di raccolta dei dati obsoleti sui sistemi moderni, ci sono buone probabilità di risparmiare alcuni cicli della CPU in questo modo. È possibile evitare di ridimensionare la mappa più volte specificando la capacità iniziale.

Una situazione in cui è preferibile clear() potrebbe essere quando l'oggetto della mappa viene condiviso tra più oggetti nel sistema. Ad esempio, se crei una mappa, assegnala a diversi oggetti e quindi mantieni alcune informazioni condivise al suo interno, impostando la mappa su una nuova in tutti questi oggetti potrebbe essere necessario mantenere i riferimenti agli oggetti che hanno la mappa. In situazioni del genere è più facile continuare a chiamare clear() sullo stesso oggetto di mappa condiviso.

+0

dalla riga "Ad esempio, se crei una mappa, assegnala a diversi oggetti ..." intendi per Mappa generica (Mappa )? – Woody

+0

@Woody Voglio dire creare una classe che implementa l'interfaccia 'Mappa - a' HashMap 'o una' TreeMap '. – dasblinkenlight

+1

@Woody - Non vedo perché sarebbe importante. Vuol dire che se ci sono diversi oggetti che hanno un riferimento alla mappa originale, allora probabilmente dovresti usare 'clear()' invece di azzerare la mappa (l'impostazione di un riferimento alla mappa su null non avrà alcun effetto su tutti gli altri riferimenti alla stessa mappa). – jahroy

2

Bene, dipende da quanta memoria è possibile lanciare. Se hai molto, allora non importa. Tuttavia, impostare la mappa su null significa che hai liberato il garbage collector - se solo la mappa ha riferimenti alle istanze al suo interno, il garbage collector può raccogliere non solo la mappa ma anche eventuali istanze al suo interno. Clear svuota la mappa ma deve scorrere su tutto nella mappa per impostare ogni riferimento su null, e questo avviene durante il tempo di esecuzione che puoi controllare - il garbage collector deve essenzialmente fare questo lavoro comunque, quindi fallo fare la sua cosa Ricorda che impostarlo su null non ti consente di riutilizzarlo. Un modello tipico di riutilizzare una variabile mappa può essere:

Map<String, String> whatever = new HashMap<String, String(); 
// .. do something with map 
whatever = new HashMap<String, String>(); 

Ciò consente di riutilizzare la variabile senza impostare a NULL a tutti, si scartano il riferimento alla vecchia mappa. Questa è una pratica atroce nelle applicazioni gestite non di memoria poiché devono fare riferimento al vecchio puntatore per cancellarlo (questo è un puntatore pendente in altri linguaggi), ma in Java poiché nulla fa riferimento a ciò, il GC lo contrassegna come idoneo per la raccolta.

+5

Lo snippet di codice non verrà compilato. Hai dichiarato il riferimento come 'finale', quindi non puoi riassegnare ciò che punta a un costruttore. – asteri

+1

Anche se è vero, non dovrebbe essere una ragione per un downvote (probabilmente ha scritto _final_ per abitudine). – jahroy

+1

@jahroy D'accordo. Non è un grosso problema e i suoi punti sono ancora validi. L'ho appena indicato per il beneficio dell'OP. – asteri

0

Ritengo nullo la mappa esistente è più economico di clear(). Poiché la creazione di oggetti è molto economica nelle moderne JVM.

0

Risposta breve: utilizzare Collection.clear() a meno che non sia troppo complicato mantenere l'arround collection.

Risposta dettagliata: In Java, l'allocazione della memoria è quasi istantanea. È più piccolo di un puntatore che viene spostato all'interno della VM. Tuttavia, l'inizializzazione di tali oggetti potrebbe aggiungere qualcosa di significativo. Inoltre, tutti gli oggetti che utilizzano un buffer interno sono sensibili al ridimensionamento e alla copia del loro contenuto. Utilizzando clear() assicurati che i buffer si stabilizzino in qualche dimensione, in modo che la riallocazione della memoria e la copia se il vecchio buffer non sarà mai necessario.

Un altro problema importante è che la riallocazione e il rilascio di molti oggetti richiederà un'esecuzione più frequente del Garbage Collector, che potrebbe causare un improvviso ritardo.

+1

@Woody Si prega di utilizzare solo 'formattazione del codice' per il codice, non l'enfasi. –

+0

@Paul Bellora, grazie Ho appena formattato il codice e corretto l'errore di battitura ("Raccoglitore di immondizie a Garbage Collector"). – Woody

+1

Sì, grazie per le correzioni, stavo scrivendo dal mio iPhone. Ci scusiamo per gli errori di battitura. – jwatkins

0

Se si mantiene sempre la mappa, verrà richiesto alla vecchia generazione. Se ogni utente ha una mappa corrispondente, il numero di mappe nella vecchia generazione è proporzionato al numero dell'utente. Può attivare il GC completo più frequentemente quando aumenta il numero di utenti.

0

È possibile utilizzare entrambi con risultati simili.

Una risposta precedente rileva che clear richiede tempo costante in un'implementazione di una mappa matura. Senza verificare il codice sorgente di Mi Piace di HashMap, TreeMap, ConcurrentHashMap, mi aspetto che il loro metodo clear richieda un tempo costante, più i costi di raccolta dei dati inutili amortized.

Un altro poster rileva che una mappa condivisa non può essere annullata. Bene, può farlo se lo vuoi, ma lo fai usando un oggetto proxy che incapsula una mappa corretta e lo annulla quando necessario. Ovviamente, dovresti implementare la classe della mappa proxy tu stesso.

Map<Foo, Bar> myMap = new ProxyMap<Foo, Bar>(); 
    // Internally, the above object holds a reference to a proper map, 
    // for example, a hash map. Furthermore, this delegates all calls 
    // to the underlying map. A true proxy. 
myMap.clear(); 
    // The clear method simply reinitializes the underlying map. 

A meno che non hai fatto qualcosa di simile a quanto sopra, clear e nulling out sono equivalenti nei modi che contano, ma penso che sia più maturo di assumere la vostra mappa, anche se non attualmente condiviso, può diventare condivisa in un secondo tempo dovuto a forze che non puoi prevedere.

C'è un altro motivo per clear invece di annullare l'operazione, anche se la mappa non è condivisa. La tua mappa può essere istanziata da un client esterno, come un factory, quindi se si cancella la mappa annullandola, si potrebbe finire coupling personalmente alla fabbrica inutilmente. Perché l'oggetto che cancella la mappa deve sapere che istanziate le vostre mappe usando Guava Maps.newHashMap() con Dio sa quali parametri? Anche se questa non è una preoccupazione realistica nel tuo progetto, vale comunque la pena di allinearti a pratiche mature.

Per i motivi di cui sopra, e a parità di tutti gli altri, vorrei votare per clear.

HTH.

+0

Sembra che 'clear 'di HashMap' richiede tempo proporzionale al numero di bucket, che può essere sublineare, superlineare o lineare nel numero di elementi a seconda del carico. 'TreeMap' presenta un metodo' clear' a tempo costante. 'ConcurrentHashMap' è più simile a' HashMap'. –