2013-08-22 5 views
27

Was sind die Vor- und Nachteile beim Leeren einer Sammlung (in meinem Fall ist es eine ArrayList) vs. Erstellen einer neuen (und lassen Sie den Müllsammler die alte löschen).Eine ArrayList leeren oder einfach eine neue erstellen und die alte Müllsammlung machen lassen?

Speziell habe ich eine ArrayList<Rectangle> namens list. Wenn eine bestimmte Bedingung auftritt, muss ich list leeren und es mit anderem Inhalt auffüllen. Soll ich list.clear() anrufen oder einfach einen neuen ArrayList<Rectangle> machen und den alten Müll sammeln lassen? Was sind die Vor- und Nachteile jedes Ansatzes?

+0

Es gibt keine Sicherheit, wann das Objekt tatsächlich Müll gesammelt wird, also würde ich denken, dass es am besten wäre, es zu leeren und wiederzuverwenden. Ich bin jedoch kein Meister mit der Speichernutzung, also bin ich daran interessiert zu sehen, welche anderen Antworten diese Antwort bekommt. – Vulcan

+0

'list.clear()' es hängt vom Kontext ab, haben Sie andere Referenzen, die sich auf dieselbe Liste beziehen? – nachokk

+0

Keine anderen Referenzen – Cricketer

Antwort

27

Sie behalten den Container und rufen clear, wenn Sie die Last auf GC reduzieren möchten: clear() löscht alle Verweise innerhalb des Arrays, aber nicht das Array für die Rückforderung durch den Garbage Collector berechtigt. Dies kann zukünftige Einfügungen beschleunigen, da das Array innerhalb von ArrayList nicht wachsen muss. Dieser Ansatz ist besonders vorteilhaft, wenn die Daten, die Sie dem Container hinzufügen möchten, ungefähr die gleiche Größe haben wie das Löschen.

Darüber hinaus müssen Sie möglicherweise clear verwenden, wenn andere Objekte einen Verweis auf das Array enthalten, das Sie gerade löschen möchten.

Das Freigeben des Containers und das Erstellen eines neuen Containers ist sinnvoll, wenn sich die Größe der neuen Daten von der vorherigen unterscheidet. Natürlich können Sie einen ähnlichen Effekt erreichen, indem Sie clear() in Kombination mit trimToSize() aufrufen. Materie

0

sie nicht wirklich ...

A List.clear() Implementierung setzt die Referenzen des internen Array auf null. Effektives Festlegen der Objekte für die Garbage Collection, wenn keine Referenzen mehr vorhanden sind.

Wenn Ihre einzige Sorge das Gedächtnis ist, gibt es keinen wirklichen messbaren Unterschied in beiden Ansätzen. Selbst in der Operation wird der Unterschied in Arrayzuweisungen (in Größenänderungsoperationen) und anderen derartigen Operationen bestehen.

Aber das Löschen kann marginal besser sein, obwohl wenn das Erstellen einer neuen Liste lesbarer ist, würde ich damit gehen.

+0

* "Wenn Ihr einziges Anliegen das Gedächtnis ist, gibt es keinen wirklichen messbaren Unterschied in beiden Ansätzen." - Eigentlich ist das nicht streng wahr. Es wird einen messbaren Unterschied geben ... wenn Sie die Menge an freiem Speicherplatz im Heap messen. (Und das ist das Ignorieren der anderen Dinge, die Sie messen können/sollten, z. B. CPU-Auslastung und Paging-Last.) –

38

Der Vorteil des Recyclings eine ArrayList (zum Beispiel durch clear Aufruf) ist, dass Sie den Aufwand für die Zuteilung eines neuen vermeiden und die Kosten für deren wachsenden ... wenn man keinen guten initialCapacity Hinweis vorsah.

Die Nachteile eines ArrayList Recycling gehören die folgenden:

  • clear() Die Methode hat null zu jedem (verwendeten) Schlitz in der ArrayList s Trägerarray zuzuordnen.

  • Die Größe clear() ändert nicht die Größe des Backing-Arrays, um Speicher freizugeben. Wenn Sie also eine Liste wiederholt ausfüllen und löschen, wird sie (permanent) mit genügend Speicher belegt, um die größte Liste darzustellen, auf die sie trifft. Mit anderen Worten, Sie haben den Speicherbedarf erhöht. Sie können das bekämpfen, indem Sie trimToSize() aufrufen ... das ein Müllobjekt usw. erstellt.

  • Es gibt Lokalität und generationenübergreifende Probleme, die die Leistung beeinträchtigen könnten. Wenn Sie ein ArrayList wiederholt wiederverwenden, wird das Objekt und sein unterstützendes Array wahrscheinlich fest sein.Das bedeutet, dass:

    • Die Liste Objekte und die Objekte, die Listenelemente sind wahrscheinlich in verschiedenen Bereichen des Haufens sein, möglicherweise zunehmenden TLB-Misses und Seite Verkehr, vor allem bei GC Zeit.

    • Zuordnung von (junge Generation) Referenzen in die Backing-Array (Tenure) Liste wahrscheinlich Schreibaufwand Overheads ... abhängig von der GC-Implementierung.


Es ist nicht möglich, genau die Leistungskompromisse für eine reale Anwendung zu modellieren. Es gibt einfach zu viele Variablen. Allerdings ist die "erhaltene Weisheit", dass das Recycling ist normalerweise keine gute Idee, wenn Sie viel Speicher haben und eine halbwegs anständige Garbage Collection.

Es ist auch erwähnenswert, dass eine moderne JVM Objekte sehr effizient zuweisen kann. Er muss lediglich auf den "freien" Zeiger des Heap aktualisieren und 2 oder 3 Objekt-Header-Wörter schreiben. Die Nullsetzung des Speichers erfolgt durch den GC ... und neben der Arbeit ist das grob entspricht der Arbeit, die clear() tut, um Referenzen in der Liste, die recycelt wird, zu vernichten.

1 - Ein Kopiersammler ist effizienter, wenn der Anteil von Müllobjekten zu Nichtabfallobjekten hoch ist. Wenn Sie die Art und Weise analysieren, in der diese Art von Kollektor arbeitet, entstehen fast alle Kosten, um erreichbare Objekte zu finden und zu kopieren. Das einzige, was mit Müllobjekten getan werden muss, ist das Blockieren-Null-Schreiben des evakuierten "Von" -Raums, bereit für die Zuweisung neuer Objekte.


Mein Rat wäre, nicht ArrayList Objekte zu recyceln, wenn Sie eine nachweisbare Notwendigkeit haben die (Müll) Objekterstellung Rate zu minimieren; z.B. weil es die einzige Option ist, die Sie haben, um (schädliche) GC-Pausen zu reduzieren.

Ceteris paribus, auf einem modernen Hotspot JVM mein Verständnis ist, dass Sie, indem Sie die folgende beste Leistung erhalten wird:

  • Allokierung neue Arraylist Objekte statt Recycling.
  • Verwenden Sie genaue initialSize Hinweise, wenn Sie die Listenobjekte zuweisen. Es ist besser, etwas zu überschätzen als zu unterschätzen.
+1

Der Ort ist der interessanteste Punkt, da er für mich weniger offensichtlich war. – marcorossi

0

Da interessante Punkte bereits geschrieben wurden, kann man noch eine Stufe tiefer darüber nachdenken.

Ich habe habe es nicht erkannt, als ich Artikel über Disruptor Muster lesen, sehen How does LMAX's disruptor pattern work?

Es ist möglich, nicht nur zu Wiederverwendung zugrunde liegenden Sammlung, können Sie Wiederverwendung auch Einheiten innerhalb die Sammlung.

z. nehmen Sie den Anwendungsfall von Produzenten und Konsumenten an. Producer kann Daten immer wieder in dasselbe (zyklische) Array füllen und sogar dieselben Entitäten verwenden.Löschen Sie einfach die Eigenschaften, den internen Status und füllen Sie sie aus.

Es ist eine Ebene bessere Lösung in Bezug auf GC Ansicht. Aber es ist offensichtlich, Sonderfall nicht für jedes Problem nützlich.

Verwandte Themen