2011-07-18 45 views
0

我有一個非常大的哈希映射(2百萬條目),它是通過讀取CSV文件的內容創建的。一些信息:減少非常大的HashMap的內存使用量

  1. HashMap將一個String鍵(它少於20個字符)映射到一個String值(大約50個字符)。
  2. 該HashMap初始化容量爲300萬,因此負載因子大約爲0.66。
  3. HashMap只被一個操作使用,一旦該操作完成,我「清除()」它。 (儘管看起來這個清除實際上並沒有清除內存,但對System.gc()的調用是必要的嗎?)。

我的一個想法是將HashMap改爲HashMap並使用String的hashCode作爲鍵,這將最終節省一些內存,但如果兩個字符串具有相同的散列碼,則存在衝突問題。 ..這對於長度小於20個字符的字符串有多大可能?

有沒有人有什麼想法在這裏做什麼? CSV文件本身只有100 MB,但是Java在這個HashMap中最終使用了超過600MB的內存。

謝謝!

+0

如何使用嵌入式數據庫(如HSQLDB或SQLite)。 http://hsqldb.org/ http://www.sqlite.org/ – Marcelo

+0

如果你想要一個唯一值,使用哈希碼總是會導致麻煩。 「可能」不是問題:哈希碼中沒有足夠的位來唯一指定一個20個字符的字符串。 – CPerkins

回答

0

如果性能不是主要問題,請將條目存儲在數據庫中。然後記憶不是一個問題,並且由於數據庫的原因,你有很好的搜尋速度(如果不是很好的話)。

+0

假設數據庫不可行,會使用內存數據庫工作嗎?我會假設它可能會使用標準的Java HashMap進行一些優化。 – Peter

0

這聽起來像你有框架來嘗試這已經。不要添加字符串,請添加string.hashCode()並查看是否碰到碰撞。

在釋放內存方面,JVM一般不會變小,但如果需要的話它會被垃圾收集。

此外,它聽起來像你可能有一個算法,根本不需要哈希表。你能詳細描述一下你想要做什麼嗎?

+0

當然,我有一個將String代碼映射到String描述的CSV。然後我有一個單獨的CSV文件,其中一列是代碼。當我處理第二個CSV文件時,我需要使用描述而不是代碼。這是生成的HashMap進場的地方。一旦完成該操作,就不再需要來自代碼 - >描述的映射。 – Peter

+0

一個想法:如果你的第二個文件沒有在第一個中使用所有的代碼,那麼先解析這個文件,然後只用你知道你需要的代碼加載你的散列表。這是通過該文件的額外運行,但如果您只需加載第一個文件的一部分,則可能值得。 – Rich

+0

另一個想法是,如果您可以按不同的順序處理第二個文件,則按ID排序第一個文件和第二個文件。然後你可以沿着第一個文件迭代,直到你看到你還沒有在第二個處理過的ID;停止處理第二個文件中的所有這些ID,繼續處理第一個文件中的下一個ID。通過這種方式,您不必在內存中存儲*任何內容,但需要按照合理的順序對文件進行排序。 – Rich

1

解析CSV並構建一個Map,其鍵是您現有的鍵,但值是Integer指針,指向該鍵的文件中的位置。

當您想要鍵值時,在映射中找到索引,然後使用RandomAccessFile從文件中讀取該行。在處理期間保持RandomAccessFile打開,然後在完成時關閉它。

1

你要做的就是一個JOIN操作。嘗試考慮像H2這樣的內存數據庫,並且可以通過將兩個CSV文件加載到臨時表來實現此目的,然後對它們進行聯接。 根據我的經驗,h2在加載操作中運行良好,並且與基於手動HashMap的加入方法相比,此代碼肯定會更快,內存更密集。