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

いちおう対象のフィードもさらっと眺めてみたけども…いまいち原因がわからないです(´・ω・`)腰据えてやらないとだめかも…

まとめ

…ということで今回は回避できたのだけども、これってなんかのバグになってるのかしら?

一応ここらへんとも関係がありそうな予感...とはっておいて、後は詳しい人にお任せします(´・ω・`)

http://scala-programming-language.1934581.n4.nabble.com/OutOfMemoryError-when-using-XMLEventReader-td2341263.html

とりあえずXhtmlParserを使った際にOut of Memoryになって泣きたくなった場合は、XML.loadStringを代わりに使うと幸せになれそうです(´・ω・`)