XhtmlParserでOut of Memoryになって泣きたくなった話
追記
どうやら環境によって起こったり起こらなかったり…な現象みたいです(´・ω・`)
現在のところ次のようなパターンで発生しております(いろいろ試して追記していきます)
発生しない環境
- Ubuntu 2.7.7final (OpenJDK Client VM, Java 1.6.0_18)
- Source.fromURL(url) のcloseなし
- パース成功
- MacOS 2.7.7final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_22)
- Source.fromURL(url) のcloseなし
- パース成功
- MacOS 2.8.1final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_22)
- パース失敗
JVMの環境な気がしてきた…他OS環境でも試してみよう…っと(´・ω・`)
元記事
scala.xml.parsing.XhtmlParserを使ってXML(RSSフィード)をパースするといつのまにかメモリを食いつぶしてしまう...という現象に遭遇したので自分メモ
上記現象が発生してはまった前のエントリーのコードを検証用にシンプルにしでみました(´・ω・`)
import scala.io.Source import scala.xml.{XML, NodeSeq} import scala.xml.parsing.XhtmlParser def feedgetter(url:String){ try{ // RSSフィードを読み込みます val source= Source.fromURL(url) // XhtmlParserを使用するとメモリを食いつぶしてしまう val feeds = XhtmlParser(source) val datas = feeds \\ "title" source.close println("success") }catch{ case e:Exception => println("parse error") } }
いまのところここらへんのURLのフィードでこけてるっぽいので…
http://feeds.feedburner.com/Mashable
http://feeds.feedburner.com/Publishing20
こんな感じで実行してみるよ(´・ω・`)
scala> feedgetter("http://feeds.feedburner.com/Mashable") // なんかメモリ領域を食いつぶされてしまいました(´;ω;`) java.lang.OutOfMemoryError: Java heap space at scala.collection.Iterator$class.toStream(Iterator.scala:1011) at scala.io.Source.toStream(Source.scala:181) at scala.collection.Iterator$$anonfun$toStream$1.apply(Iterator.scala:1011) at scala.collection.Iterator$$anonfun$toStream$1.apply(Iterator.scala:1011) at scala.collection.immutable.Stream$Cons.tail(Stream.scala:565) at scala.collection.immutable.Stream$Cons.tail(Stream.scala:557) at scala.collection.LinearSeqLike$$anon$1.next(LinearSeqLike.scala:57) at scala.io.Source$Positioner.next(Source.scala:260) at scala.io.Source.next(Source.scala:243) at scala.io.Source.next(Source.scala:181) at scala.collection.Iterator$class.toStream(Iterator.scala:1011) at scala.io.Source.toStream(Source.scala:181) at scala.collection.Iterator... scala>
ちなみに上記以外のURLで実行すると無問題...ってどういうこと...orz
// パース成功の場合は当然問題なく(´・ω・`) scala> v success // 失敗したとしてもメモリ食いつぶすような事はしないです scala> feedgetter("http://journals.aol.com/thecoolerblog/AOLNewsCooler/rss.xm")) parse error
XML.loadStringを使用した場合
どうしようもなくなったので、代替手段として下記のようにXML.loadStringを使ってRSSフィードを読み込むようにしてやります
def feedgetter(url:String){ try{ val source= Source.fromURL(url) // XhtmlParserの代わりにXML.loadStringを使用します val feeds = XML.loadString(source.getLines.mkString) val datas = feeds \\ "title" source.close println("success") }catch{ case e:Exception => println("parse error") } }
実行結果はこんな感じです
// ちゃんとパースで来てるっぽいし(´・ω・`) scala> feedgetter("http://feeds.feedburner.com/Mashable") success
いちおう対象のフィードもさらっと眺めてみたけども…いまいち原因がわからないです(´・ω・`)腰据えてやらないとだめかも…
まとめ
…ということで今回は回避できたのだけども、これってなんかのバグになってるのかしら?
一応ここらへんとも関係がありそうな予感...とはっておいて、後は詳しい人にお任せします(´・ω・`)
とりあえずXhtmlParserを使った際にOut of Memoryになって泣きたくなった場合は、XML.loadStringを代わりに使うと幸せになれそうです(´・ω・`)