2010-05-19 57 views
7

我正在編寫一個編解碼器來處理使用定製的有線協議通過TCP發送的消息。在解碼過程中,我創建了一些String s,BigDecimal s和日期。客戶端 - 服務器的訪問模式意味着它是很常見的客戶端發出請求,然後解碼上千響應消息,這會導致大量的重複String S,BigDecimal S等使用PermGen空間或roll-my-own實習生方法?

所以我創建了一個InternPool<T>類,允許我實習每一類對象。在內部,池使用WeakHashMap<T, WeakReference<T>>。例如:

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

... 

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

我的問題:我使用InternPoolBigDecimal但我應該還可以考慮使用它String,而不是Stringintern()方法,我相信使用的PermGen空間?使用PermGen空間的優點是什麼?

+1

@kts:如果我將byte []映射到BigDecimal,那麼一旦Intern池創建/返回了BigDecimal,byte []將不會被任何內容引用。假設byte []是底層WeakHashMap中的鍵,這將導致該條目被刪除,儘管正在使用相應的BigDecimal。 – Adamski 2010-05-19 12:32:14

+1

WeakReference適合這個,還是應該使用'SoftReference'? GC的行爲不同,這聽起來像你試圖創建一種緩存;弱引用不適合用於此目的。看到我的答案在這裏,爲什麼一些原因:http://stackoverflow.com/questions/2861410/weakhashmap-iteration-and-garbage-collection/2862174#2862174 – 2010-05-19 14:58:57

+0

@Adamski我會只使用BigDecimal SoftReference和ReferenceQueue一旦BigDecimal入隊,從地圖中刪除'byte []'s。 (可能需要BiMap)。這可以避免構建冗餘的BigDecimal對象,從而節省內存/ gc運行時和執行時間(只需構造一次)。 – KitsuneYMG 2010-05-19 15:11:50

回答

2

JVM的String.intern()池可能會更快。 AFAIK,它是以本地代碼實現的,因此理論上它應該比使用WeakHashMapWeakReference實現的池更快,佔用空間更少。你需要做一些仔細的基準測試來證實這一點。

但是,除非您有大量的長壽命重複對象,否則我懷疑實習(無論是在permGen還是在您自己的池中)都會產生很大的差異。並且如果唯一對象重複的比例太低,則實習會增加活動對象的數量(使GC花費更長時間),並由於實習等開銷而降低性能。所以我也會主張將「實習生」與「無實習生」的方法進行比較。

+0

Adamski確實擁有大量的長壽複製對象:-) – 2010-07-15 23:57:00

+0

@oxbow_lakes - 非常聰明。關鍵是你需要量化這些事情來確定實習(通過什麼機制)是否會提高績效......或者使情況變得更糟。有很多因素影響結果。 – 2010-07-16 00:33:40

4

如果你已經有這樣一個InternPool類,它認爲最好使用它,而不是爲Strings選擇不同的實施方法。特別是因爲String.intern()似乎提供了比你實際需要更強大的保證。您的目標是減少內存使用量,因此JVM生命週期中的完美實習並不是必需的。

而且,我會用Google CollectionsMapMaker創建InternPool以避免重新創建輪:

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

這將使你(正確實施)弱鍵和值,線程安全,自動清除舊的條目和一個非常簡單的界面(一個簡單的,衆所周知的Map)。可以肯定的是,你也可以使用Collections.immutableMap()來包裝它,以避免糟糕的代碼與它混淆。

+0

好的,謝謝。 String.intern()是否爲JVM的生命期實習生?我不確定這是否屬實,因爲我認爲從PermGen收集現代虛擬機垃圾。 – Adamski 2010-05-19 11:51:36

+0

@Joachim - 你似乎暗示了一個實際的字符串將在JVM的生命中生存。這不是由javadocs保證的,事實上我認爲最近的JVM並不是這樣。 – 2010-05-19 11:53:12

+0

@Stephen:我試着*不*暗示,因爲JavaDoc確實沒有說明。 – 2010-05-19 16:07:12