2013-04-12 45 views
1

所以。我正在使用Scala,而且我對它相對比較陌生(主要是一個python傢伙)。我正在編譯並通過sbt運行我的代碼。我在一個Ubuntu機器上,目前運行Java 6。我有兩個CSV;我需要把他們,處理他們,然後操縱他們。每個CSV是〜250MB;如果這有效,我可能會用更大的CSV重複此過程。斯卡拉超大CSV CSV讀取的GC開銷限制

我已經定義了一個讀取CSV並將每行寫入我需要的數據結構的函數。我在每個CSV系列中調用此函數。問題是:第一個CSV完美(並且非常快)返回,但第二個總是拋出java.lang.OutOfMemoryError: GC overhead limit exceeded錯誤。

我試過了很多東西。我的build.sbt定義了javaOptions += "-Xmx20480m -XX:+HeapDumpOnOutOfMemoryError";我也嘗試過使用-XX:-UseGCOverheadLimit,但這似乎沒有任何幫助。根據我一直在閱讀的Java文檔,這個錯誤表明大量的系統資源被用於垃圾回收 - 但我坦率地不清楚它是什麼垃圾收集,或者如何修剪它。我認爲我的功能必須......泄漏內存,或者我必須錯誤地使用Scala,但我看不出如何。

這裏是我的功能:

def readAndProcessData(path: String) = { 
    val fileLines = Source.fromFile(path).getLines.drop(1) 
    val ret = mutable.Map[String, List[Tuple2[String, String]]]() 

    def addRowToRet(row: String) = { 
     val rowArray = row.split(",") 
     if (!(ret contains rowArray(0))) { 
      ret.update(rowArray(0), List[Tuple2[String, String]]()) 
     } 
     ret(rowArray(0)) = Tuple2(rowArray(1), rowArray(2)) :: ret(rowArray(0)) 
    } 

    for (row <- fileLines) { 
     addRowToRet(row) 
    } 

    ret.map{tup => (tup._1 -> tup._2.sorted)} 

} 

謝謝!

+0

使用循環does not看起來Scala'ish。 1.使用filelines.foldLeft將csv數據轉換爲地圖。 2.儘量使addRowtoRet遞歸 – Rajesh

+0

如果你仍然想要去相同的代碼嘗試使用ret.par.map {TUP =>(tup._1 - > tup._2.sorted)} – Rajesh

+0

你在SBT運行時分叉? javaOptions僅用於如果sbt派生一個新進程來運行你的程序,這不是默認行爲。 –

回答

6

首先,如果你沒有分叉運行,要麼enable forking要麼增加sbt的內存限制並刪除javaOptions設置。分叉可能是一個好主意,所以你不會混淆你的程序的內存使用行爲和sbt的行爲。

您也應關閉您正在創建的Source對象,以確保其資源已發佈。

它是否在一致的地方崩潰,例如排序時?或者崩潰發生在代碼中相當隨機的地方?

我假設你正在閱讀的文件是以ASCII或UTF8編碼的,其中大多數字符都是用8位表示的。 Java使用每個字符16位,所以請記住,通過將它讀入Java字符串中,您的大小會增加一倍以上(「多於」是由於其他開銷)。這本身不應該推動你,但這意味着當你有兩個250MB的文件加載時,你可能會消耗超過1GB的數據內存。

你的密鑰相對於文件中行數的分佈情況如何?換句話說,你的地圖中是否有幾乎每條線的條目,大約一半的線,四分之一等?你可能會有一個非常大的地圖(在條目方面),當你執行操作它的「地圖」來對值進行排序時,你最終會記住它們中的兩個,直到函數返回並且舊函數變爲可收集。您也可能想嘗試使用不可變映射或Java可變映射的包裝。有時Scala的可變數據結構不如它們不可變的數據結構那樣健壯。

此外,我從來沒有與scala.io.Source的好運氣。如果在相當確定的情況下它仍然失敗,那麼實際上已經分配了足夠的內存,您可能需要嘗試使用Java的IO庫。

最後,如果檢查一些設置並戳一下不起作用,則應該將內存分析器連接到它,例如VisualVM。那就是你在找出問題所在,而不是通過修改來進行猜測和檢查的時候有所準備。

+0

您的建議,以使分叉似乎已經基本立即解決了這個問題!非常感謝你在這裏的時間 - 你給了我很多其他非常好的信息,這是很好的地獄。到目前爲止,在我的運行中啓用分叉已經解決了一切 - 輝煌! – Gastove

0

嘗試返回ret並將其映射到包裝方法中。這應該避免將所有內容都放在內存中。

相關問題