2015-03-03 70 views
4

我很驚訝,這會引發內存不足錯誤,因爲操作是在scala.collection.Iterator的頂部。各條線的尺寸小(< 1KB)令人驚訝的Scala迭代器「內存不足」錯誤

Source.fromFile("largefile.txt").getLines.map(_.size).max 

似乎它試圖加載整個文件在存儲器中。不知道哪一步觸發了這一點。對於這樣的基本操作來說,這是令人失望的行爲。有沒有簡單的方法呢。這是由圖書館實施者設計的原因嗎?

在Java8中嘗試相同。

Files.lines(Paths.get("largefile.txt")).map(it -> it.length()).max(Integer::max).get 
//result: 3131 

而且這個工作可以預測。 Files.lines返回java.util.stream.Stream並且堆不會爆炸。

更新:看起來像歸結爲新的線解釋。兩個文件都被解釋爲UTF-8,並且它們都調用java.io.BufferedReader.readLine()。所以,仍然需要找出差異在哪裏。我將兩個片段主要類編譯到同一個項目jar中。

+0

很多...文件大小比堆大小大。那不是重點。我認爲這不重要,因爲它是一個迭代器。 – smartnut007 2015-03-03 02:29:59

+3

重現這個文件有多大?我只是在10 GB上運行,沒有任何問題。 – 2015-03-03 03:43:14

+5

你確定*每行少於1KB?如果沒有任何換行符,那麼調用'_.size'將會生成一個非常大的'String'並且很快耗盡內存。 – 2015-03-03 03:53:10

回答

3

我願意成爲的問題是,你要計數的'線'不同於getLines。從API:

(getLines)返回誰返回線(不包括換行字符 (S))的迭代器。它會將\ r \ n,\ r或\ n當作行 分隔符(最長匹配) - 如果您需要更精細的行爲,可以直接使用 子類Source#LineIterator。

嘗試在問題執行此對文件:

Source.fromFile("testfile.txt").getLines(). 
    zipWithIndex.map{ case(s, i) => (s.length, i)}. 
     foreach(e=> if (e._1 > 1000) println(
     "line: " + e._2 + " is: " + e._1 + " bytes!")) 

這會告訴你許多文件中的行如何大於1K的,什麼指數是違規行。

+0

- 如果在打印任何東西前發生這種情況 - 您可以輕鬆地重構此行來打印/記錄每一行的行號 - 這也將幫助您找到問題的索引。 – 2015-03-03 19:20:18

+0

根本沒有解決我的問題。抱歉。 – smartnut007 2015-03-04 02:25:51

+1

@ smartnut007 - 是的,它確實如此。你假設你沒有犯錯,但沒有顯示你是如何得出這個結論的。我,Ben Reich,m-z和Aleksey Izmailov都表達了基本相同的觀點 - 這個問題可能是程序員的錯誤。因此,你爲什麼不告訴我們它不是?當你運行上面的代碼時,你會得到什麼輸出?您對Ben Reich的評論是什麼迴應,他無法用10GB文件重現您的結果? – 2015-03-04 16:23:10