2013-08-22 2 views
27

Quali sono i vantaggi e gli svantaggi dello svuotamento di una raccolta (nel mio caso si tratta di una ArrayList) rispetto alla creazione di una nuova (e consentendo al garbage collector di cancellare quello precedente).Svuota una lista array o semplicemente creane una nuova e lascia che la vecchia sia raccolta dei rifiuti?

In particolare, ho un ArrayList<Rectangle> chiamato list. Quando si verifica una determinata condizione, ho bisogno di svuotare list e riempirlo con altri contenuti. Devo chiamare lo list.clear() o semplicemente creare un nuovo ArrayList<Rectangle> e lasciare che quello vecchio venga raccolto? Quali sono i pro e i contro di ciascun approccio?

+0

Non c'è alcuna garanzia di quando l'oggetto sarà effettivamente raccolto dai rifiuti, quindi penserei che lo svuotamento e il riutilizzo sarebbero i migliori. Non sono un maestro con l'uso della memoria, quindi sarei interessato a vedere quali altre risposte questa risposta ottiene. – Vulcan

+0

'list.clear()' dipende dal contesto, hai altri riferimenti che si riferiscono alla stessa lista? – nachokk

+0

Nessun altro riferimento – Cricketer

risposta

27

Si mantiene il contenitore e si chiama clear quando si desidera ridurre il carico su GC: clear() annulla tutti i riferimenti all'interno dell'array, ma non rende l'array idoneo per il recupero da parte del garbage collector. Ciò potrebbe accelerare gli inserimenti futuri, perché la matrice all'interno di ArrayList non ha bisogno di crescere. Questo approccio è particolarmente vantaggioso quando i dati che si intende aggiungere al contenitore hanno all'incirca le stesse dimensioni di quando si elimina.

Inoltre, potrebbe essere necessario utilizzare clear quando altri oggetti contengono un riferimento alla matrice che si sta per cancellare.

Rilasciare il contenitore e crearne uno nuovo ha senso quando la dimensione dei nuovi dati potrebbe essere diversa da quella precedente. Ovviamente è possibile ottenere un effetto simile chiamando lo clear() in combinazione con trimToSize().

0

Non ha molta importanza ...

A List.clear() implementazione imposta riferimenti della matrice interna a null. Impostare in modo efficace gli oggetti da raccogliere se non ci sono più riferimenti.

Se la tua unica preoccupazione è la memoria, non c'è una reale differenza misurabile in entrambi gli approcci. Anche per quanto riguarda l'operazione, la differenza sarà nelle allocazioni dell'array (nelle operazioni di ridimensionamento) e in altre operazioni simili.

Ma la compensazione potrebbe essere leggermente migliore anche se la creazione di una nuova lista è più leggibile.

+0

* "Se la tua unica preoccupazione è la memoria non c'è una reale differenza misurabile in entrambi gli approcci." * - In realtà, questo non è strettamente vero. Ci sarà una differenza misurabile ... se si misura la quantità di spazio libero nell'heap. (E questo è ignorando le altre cose che puoi/dovresti misurare, ad esempio utilizzo della CPU e carico di paging.) –

38

Il vantaggio di riciclare un ArrayList (per esempio chiamando clear) è che si evita il sovraccarico di allocare una nuova, e il costo di crescere ... se non hai fornito una buona initialCapacity suggerimento.

Gli svantaggi di riciclaggio un ArrayList sono i seguenti:

  • Procedimento clear() deve assegnare a ciascun null (usato) fessura nella ArrayList s matrice di supporto.

  • Il clear() non ridimensiona l'array di supporto per rilasciare memoria. Quindi, se si riempie e cancella ripetutamente un elenco, questo finirà (permanentemente) usando abbastanza memoria per rappresentare l'elenco più grande che incontra. In altre parole, hai aumentato l'ingombro della memoria. Puoi combatterlo chiamando lo trimToSize() ... che crea un oggetto spazzatura, eccetera.

  • Esistono problemi di località e intergenerazionali che possono influire sulle prestazioni. Quando si ricicla ripetutamente un ArrayList, è probabile che l'oggetto e il relativo array di supporto vengano gestiti.Ciò significa che:

    • Gli oggetti di elenco e gli oggetti che rappresentano elementi della lista sono suscettibili di essere in diverse aree del mucchio, aumentando potenzialmente manca TLB e traffico pagina, in particolare in fase di GC.

    • L'assegnazione di riferimenti (di nuova generazione) nel backing array della lista (di proprietà dei supporti) è probabile che incorre in sovraccarichi di barriera di scrittura ... a seconda dell'implementazione del GC.


Non è possibile modellare accuratamente i compromessi di prestazioni per un'applicazione reale. Ci sono troppe variabili. Tuttavia, la "saggezza ricevuta" è che il riciclaggio NON è normalmente una buona idea se si ha un sacco di memoria e un raccoglitore di rifiuti decente.

Vale anche la pena notare che una JVM moderna può allocare oggetti in modo molto efficiente. Ha solo bisogno di aggiornare il puntatore "libero" dell'heap e scrivere 2 o 3 parole di intestazione dell'oggetto. L'azzeramento della memoria viene eseguito dal GC ... e inoltre il lavoro svolto è pari a equivalente al lavoro che clear() esegue per annullare i riferimenti nell'elenco che viene riciclato.

1 - Un raccoglitore di copie è più efficiente se la percentuale di oggetti inutili su oggetti non obsoleti è elevata. Se analizzi il modo in cui funziona questo tipo di raccoglitore, i costi sono quasi tutti sostenuti per trovare e copiare oggetti raggiungibili. L'unica cosa che deve essere fatta per gli oggetti spazzatura è scrivere a zero zero lo spazio "da" evacuato per l'allocazione di nuovi oggetti.


Il mio consiglio sarebbe di non riciclare ArrayList oggetti a meno che non si dispone di una necessità dimostrabile per ridurre al minimo il (spazzatura) tasso di creazione di oggetti; per esempio. perché è l'unica opzione disponibile per ridurre le pause GC (dannose).

A parità di condizioni, su una moderna Hotspot JVM la mia comprensione è che si ottengono migliori prestazioni nel modo seguente:

  • L'assegnazione di nuovi oggetti ArrayList invece di riciclaggio.
  • Utilizzare gli accurati spunti initialSize quando si assegnano gli oggetti elenco. È meglio sovrastimare leggermente di leggermente sottostimare.
+1

il punto di località è il più interessante, per me era il meno ovvio. – marcorossi

0

Come punti di interesse erano già stati scritti, puoi pensarci anche a un livello più profondo.

ho non ho capito quanto ho letto l'articolo su modello distruttore, vedere How does LMAX's disruptor pattern work?

E 'possibile non solo per il riutilizzo sottostante raccolta, è possibile riutilizzare anche entità all'interno la collezione.

E.g. supponiamo che il produttore e il caso d'uso del consumatore. Il produttore può riempire i dati nello stesso (ciclico) array ripetutamente e persino utilizzare le stesse entità.Basta cancellare le proprietà, lo stato interno e riempirlo.

È la soluzione di un livello migliore nel punto di vista GC. Ma ovviamente è un caso speciale non utile per ogni problema.