2013-10-24 16 views
12

Ich habe eine Karte, die ich verwende, um dynamische Daten zu speichern, die verworfen werden, sobald sie erstellt werden (d. H. Verwendet; sie werden schnell verbraucht). Es reagiert auf die Benutzerinteraktion in dem Sinne, dass, wenn ein Benutzer auf eine Schaltfläche klickt, die Karte gefüllt wird und dann die Daten verwendet werden, um etwas Arbeit zu leisten, und dann wird die Karte nicht länger benötigt.Map clear vs null

Also meine Frage ist, was ist ein besserer Ansatz zum Leeren der Karte? sollte ich es jedes Mal auf null setzen oder sollte ich clear() anrufen? Ich weiß, klar ist linear in der Zeit. Aber ich weiß nicht, wie man diese Kosten mit denen der Karte jedes Mal vergleichen kann. Die Größe der Karte ist nicht konstant, es kann von n bis 3n Elementen zwischen den Kreationen laufen.

Antwort

7

Wenn eine Karte nicht von anderen Objekten referenziert wird, wo es schwierig sein kann, um einen neuen zu setzen, einfach null -ing eine alte Karte und von Grunde auf neu ist wahrscheinlich leichtes Gewicht als ein clear() nennen, weil keine linear- Zeitaufräumung muss passieren. Da die Kosten für die Müllsammlung auf modernen Systemen gering sind, besteht eine gute Chance, dass Sie auf diese Weise einige CPU-Zyklen sparen. Sie können die Größe der Map nicht mehrfach ändern, indem Sie die Anfangskapazität angeben.

Eine Situation, in der clear() bevorzugt wird, wäre, wenn das Kartenobjekt unter mehreren Objekten in Ihrem System geteilt wird. Wenn Sie beispielsweise eine Karte erstellen, sie mehreren Objekten zuweisen und dann einige gemeinsam genutzte Informationen darin aufbewahren, müssen Sie bei der Festlegung der Karte auf eine neue Karte in allen diesen Objekten möglicherweise Verweise auf Objekte mit der Karte beibehalten. In solchen Situationen ist es einfacher, clear() für dasselbe gemeinsame Kartenobjekt aufzurufen.

+0

aus der Zeile "Zum Beispiel, wenn Sie eine Karte erstellen, geben Sie es an mehrere Objekte ..." meinst du für generische Karte (Map )? – Woody

+0

@Woody Ich meine eine Klasse zu erstellen, die die 'Map ' Schnittstelle implementiert - eine' HashMap 'oder eine' TreeMap '. – dasblinkenlight

+1

@Woody - Ich sehe nicht, warum es wichtig wäre. Er meint, dass, wenn mehrere Objekte einen Bezug auf die ursprüngliche Map haben, Sie wahrscheinlich 'clear()' anstelle der Nullung der Map verwenden müssen (wenn Sie einen Verweis auf die Map auf null setzen, wirkt sich dies nicht auf alle aus die anderen Referenzen auf die gleiche Karte). – jahroy

2

Nun, es hängt davon ab, wie viel Speicher Sie darauf werfen können. Wenn du viel hast, dann ist es egal. Wenn Sie jedoch die Zuordnung selbst auf null setzen, bedeutet dies, dass Sie den Garbage Collector freigegeben haben. Wenn nur die Zuordnung Verweise auf die darin enthaltenen Instanzen enthält, kann der Garbage Collector nicht nur die Map, sondern auch alle Instanzen darin sammeln. Clear löscht die Map, aber es muss über alles in der Map iterieren, um jeden Verweis auf null zu setzen, und dies geschieht während der Ausführungszeit, die Sie steuern können - der Müllsammler muss diese Arbeit sowieso tun, also lassen Sie es tun seine Sache. Beachten Sie, dass Sie diese Option nicht auf Null setzen können. Ein typisches Muster, das eine Karte Variable wiederzuverwenden können sein:

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

Auf diese Weise können Sie die Variable wiederverwenden, ohne Einstellung sie überhaupt auf null, Sie lautlos den Verweis auf die alte Karte verwerfen. Dies ist eine grausame Übung in nicht speicherverwalteten Anwendungen, da sie auf den alten Zeiger verweisen müssen, um ihn zu löschen (dies ist ein schwebender Zeiger in anderen Sprachen), aber in Java, da nichts darauf verweist, markiert der GC ihn für die Sammlung.

+5

Ihr Code-Snippet wird nicht kompiliert. Sie haben die Referenz als "final" deklariert, sodass Sie nicht neu zuweisen können, auf was sie mit einem Konstruktor zeigt. – asteri

+1

Während das stimmt, sollte es kein Grund für einen Downvote sein (er schrieb wahrscheinlich aus Gewohnheit "final"). – jahroy

+1

@Jahry Einverstanden. Es ist keine große Sache und seine Punkte sind immer noch gültig. Ich habe nur auf den Nutzen des OP hingewiesen. – asteri

0

Ich fühle mich das Nullen der bestehenden Karte ist billiger als clear(). Wie die Schaffung von Objekten in modernen JVMs sehr billig ist.

0

Kurze Antwort: Verwenden Sie Collection.clear(), es sei denn, es ist zu kompliziert, um die collection arround zu halten.

Detaillierte Antwort: In Java ist die Zuweisung von Speicher fast sofort. Es ist wenig mehr als ein Zeiger, der innerhalb der VM bewegt wird. Die Initialisierung dieser Objekte kann jedoch zu etwas Bedeutendem führen. Außerdem sind alle Objekte, die einen internen Puffer verwenden, für die Größenänderung und das Kopieren ihres Inhalts sinnvoll. Stellen Sie mithilfe von clear() sicher, dass sich die Puffer schließlich auf eine bestimmte Größe stabilisieren, so dass die Neuzuweisung von Speicher und das Kopieren des alten Puffers in den neuen Puffer nie erforderlich sein wird.

Ein weiteres wichtiges Problem ist, dass das erneute Zuweisen und anschließende Freigeben vieler Objekte eine häufigere Ausführung des Garbage Collectors erfordert, was zu einer plötzlichen Verzögerung führen kann.

+1

@Woody Bitte benutzen Sie 'Code Formatierung' nur für Code, nicht für Hervorhebung. –

+0

@Paul Bellora, danke ich habe gerade den Code formatiert und den Tippfehler korrigiert ("Grabage Collector to Garbage Collector"). – Woody

+1

Ja, danke für die Korrekturen, ich schrieb von meinem iPhone. Entschuldigung für die Tippfehler. – jwatkins

0

Wenn Sie die Karte immer halten, wird sie zur alten Generation aufgefordert. Wenn jeder Benutzer über eine entsprechende Karte verfügt, ist die Anzahl der Karten in der alten Generation proportional zur Anzahl der Benutzer. Es kann Full GC häufiger auslösen, wenn die Anzahl der Benutzer zunimmt.

0

Sie können beide mit ähnlichen Ergebnissen verwenden.

Eine vorherige Antwort merkt an, dass clear erwartet wird, konstante Zeit in einer reifen Kartenimplementierung zu nehmen. Ohne Überprüfung des Quellcodes von Likes von HashMap, TreeMap, ConcurrentHashMap, würde ich erwarten, dass ihre clear Methode dauernde Zeit plus amortized Müllsammlungskosten dauert.

Ein anderes Poster weist darauf hin, dass eine freigegebene Karte nicht gelöscht werden kann. Nun, es kann, wenn Sie es wollen, aber Sie tun es, indem Sie ein proxy Objekt verwenden, das eine richtige Karte einkapselt und es bei Bedarf auf Null setzt. Natürlich müssten Sie die Proxy-Map-Klasse selbst implementieren.

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. 

Es sei denn, du hast so etwas wie die oben, clear und nulling sind aus entsprechenden Betrag in der Art und Weise, dass die Materie, aber ich denke, es reifere ist Ihre Karte zu übernehmen, auch wenn sie derzeit nicht geteilt wird, zu einem späteren geteilt werden könnte Zeit aufgrund von Kräften, die Sie nicht vorhersehen können.

Es gibt einen anderen Grund, clear anstelle von Nullen, auch wenn die Karte nicht geteilt wird. Ihre Karte kann von einem externen Client instanziiert werden, z. B. factory. Wenn Sie Ihre Karte also löschen, indem Sie sie auf Null setzen, könnten Sie sich selbst unnötig in der Fabrik belassen coupling. Warum sollte das Objekt, das die Karte löscht, wissen, dass Sie Ihre Karten mit Guavas Maps.newHashMap() mit Gott weiß welche Parameter instanziieren? Auch wenn dies in Ihrem Projekt kein realistisches Anliegen ist, lohnt es sich dennoch, sich an ausgereifte Praktiken zu orientieren.

Aus den oben genannten Gründen und unter sonst gleichen Bedingungen würde ich für clear stimmen.

HTH.

+0

Es scheint, '' HashMap's 'clear' nimmt Zeit proportional zur Anzahl der Buckets, die in der Anzahl der Elemente in Abhängigkeit von der Belastung, kann sublinear, superlinear oder linear sein. 'TreeMap' bietet eine konstante Zeit' clear' Methode. 'ConcurrentHashMap' ist mehr in Richtung 'HashMap'. –