2010-05-19 7 views
7

Ich schreibe einen Codec, um Nachrichten zu verarbeiten, die über TCP mit einem maßgeschneiderten Kabelprotokoll gesendet werden. Während des Dekodierungsprozesses erstelle ich eine Anzahl von String s, BigDecimal s und Daten. Die Client-Server-Zugriffsmuster bedeuten, dass es üblich ist, dass der Client eine Anforderung zur Ausgabe und dann Tausende von Antwortnachrichten, die in einer großen Anzahl von DuplikatString s, BigDecimal s usw.Verwenden Sie PermGen Space oder Roll-My-Own intern Methode?

Daher ergeben dekodieren I habe eine InternPool<T> Klasse erstellt, die es mir erlaubt, jede Klasse von Objekten zu internieren. Intern verwendet der Pool eine WeakHashMap<T, WeakReference<T>>. Zum Beispiel:

InternPool<BigDecimal> pool = new InternPool<BigDecimal>(); 

... 

// Read BigDecimal from in buffer and then intern. 
BigDecimal quantity = pool.intern(readBigDecimal(in)); 

Meine Frage: Ich verwende InternPool für BigDecimal aber soll ich benutze es auch für StringstattString ‚s intern() Methode, die ich glaube, verwendet PermGen Raum? Was ist der Vorteil der Verwendung von PermGen-Speicherplatz?

+1

@kts: Wenn ich Byte [] zu BigDecimal zuordnen würde, dann ist das Problem, dass Byte [] nicht referenziert wird, sobald der interne Pool das BigDecimal erstellt/zurückgegeben hat. Unter der Annahme, dass das Byte [] der Schlüssel in der zugrundeliegenden WeakHashMap ist, würde dies dazu führen, dass der Eintrag entfernt wird, obwohl das entsprechende BigDecimal verwendet wird. – Adamski

+1

Ist 'WeakReference' dafür geeignet, oder sollten Sie lieber eine' SoftReference' verwenden? Der GC verhält sich für beide unterschiedlich und das klingt, als ob Sie versuchen, eine Art Cache zu erstellen. schwache Referenzen sind für diesen Zweck nicht gut geeignet. Siehe meine Antwort hier aus einigen Gründen, warum: http://StackOverflow.com/Questions/2861410/weakhashmap-iteration-and-garbage-collection/2862174#2862174 –

+0

@Adamski Ich würde eine SoftReference nur für die BigDecimal und eine ReferenceQueue verwenden Entferne 'byte []' s von der Karte, sobald ein BigDecimal in die Warteschlange gestellt wurde. (Wahrscheinlich brauche ich eine BiMap).Dies kann den Aufbau von redundanten BigDecimal-Objekten eliminieren, wodurch Speicher-/GC-Laufzeit und Ausführungszeit eingespart werden (muss nur einmal konstruiert werden). – KitsuneYMG

Antwort

2

Es ist möglich, dass der JVM-Pool String.intern() schneller ist. AFAIK, ist es in nativen Code implementiert, so in der Theorie sollte schneller sein und weniger Speicherplatz als ein Pool mit WeakHashMap und WeakReference implementiert verwenden. Sie müssten ein sorgfältiges Benchmarking durchführen, um dies zu bestätigen.

Allerdings, wenn Sie eine große Anzahl von langlebigen doppelten Objekten haben, bezweifle ich, dass Interning (entweder in permGen oder mit Ihren eigenen Pools) viel Unterschied machen wird. Und wenn das Verhältnis von eindeutigen zu doppelten Objekten zu niedrig ist, erhöht das Internieren nur die Anzahl der Live-Objekte (wodurch der GC länger dauert) und verringert die Leistung aufgrund der Gemeinkosten des Praktikums und so weiter. Daher würde ich mich auch für ein Benchmarking der Ansätze "intern" und "nicht intern" einsetzen.

+0

Adamski hat tatsächlich eine große Anzahl von langlebigen, doppelten Objekten :-) –

+0

@oxbow_lakes - sehr schlau. Der Punkt ist, dass Sie diese Dinge quantifizieren müssen, um herauszufinden, ob Internieren (durch welchen Mechanismus auch immer) die Leistung verbessert ... oder es verschlimmert. Und es gibt eine Menge Faktoren, die den Effekt beeinflussen. –

4

Wenn Sie bereits eine solche InternPool Klasse haben, denken Sie, dass es besser ist, das zu verwenden, als eine andere Internierungsmethode für Strings zu wählen. Zumal String.intern() scheint eine viel stärkere Garantie zu geben, als Sie tatsächlich benötigen. Ihr Ziel ist es, die Speichernutzung zu reduzieren, so dass ein perfektes Praktikum für die Lebensdauer der JVM nicht wirklich notwendig ist.

Auch würde ich die Google CollectionsMapMaker verwenden, um ein InternPool zu erstellen neu zu erstellen, um das Rad zu vermeiden:

Map<BigDecimal,BigDecimal> bigDecimalPool = new MapMaker() 
    .weakKeys() 
    .weakValues() 
    .expiration(1, TimeUnits.MINUTES) 
    .makeComputingMap(
     new Function<BigDecimal, BigDecimal>() { 
     public BigDecimal apply(BigDecimal value) { 
      return value; 
     } 
     }); 

Dies würden Sie (richtig implementiert) schwache Schlüssel und Werte, Thread-Sicherheit, automatische Spülung von alten Einträgen und eine sehr einfache Schnittstelle (eine einfache, bekannte Map). Um sicher zu sein, könnten Sie es auch mit Collections.immutableMap() umhüllen, um einen schlechten Code damit zu vermeiden.

+0

OK Danke. Ist String.intern() Praktikant für die Lebenszeit der JVM? Ich bin mir nicht sicher, ob das stimmt, da ich dachte, dass moderne VMs aus PermGen stammen. – Adamski

+0

@Joachim - Sie scheinen zu implizieren, dass ein internierter String für das Leben der JVM leben wird. Dies wird von den Javadocs nicht garantiert, und in der Tat glaube ich nicht, dass dies für die letzten JVMs der Fall ist. –

+0

@Stephen: Ich habe versucht * nicht *, das zu implizieren, wie das JavaDoc tatsächlich nicht besagt. –

Verwandte Themen