使用net.liftweb.json或scala.util.parsing.json解析大型(30MB)JSON文件会产生OutOfMemoryException。有什么建议?

时间:2012-01-17 16:42:13

标签: json scala lift

我有一个包含大量测试数据的JSON文件,我想要解析并推送我正在测试的算法。它的大小约为30MB,列表中有大约60,000个元素。我最初尝试使用scala.util.parsing.json中的简单解析器,如下所示:

import scala.util.parsing.json.JSON
val data = JSON.parseFull(Source.fromFile(path) mkString)

其中path只是一个包含大JSON文件路径的字符串。那拉了大约45分钟,然后扔了这个:

java.lang.OutOfMemoryError: GC overhead limit exceeded

然后有人向我指出没有人使用这个库我应该使用Lift的JSON解析器。所以我在Scala REPL中尝试了这个:

scala> import scala.io.Source
import scala.io.Source

scala> val s = Source.fromFile("path/to/big.json")
s: scala.io.BufferedSource = non-empty iterator

scala> val data = parse(s mkString)
java.lang.OutOfMemoryError: GC overhead limit exceeded

这次只花了大约3分钟,但同样的错误。

所以,显然我可以将文件分解成更小的文件,遍历JSON文件的目录并将我的数据一块一块地合并在一起,但是如果可能的话我宁愿避免它。有没有人有任何建议?

有关详细信息 - 过去几周我一直在Clojure中使用相同的数据集(用于与Incanter进行可视化)而没有任何问题。以下工作完全正常:

user=> (use 'clojure.data.json)
nil
user=> (use 'clojure.java.io)
nil

user=> (time (def data (read-json (reader "path/to/big.json"))))
"Elapsed time: 19401.629685 msecs"
#'user/data

2 个答案:

答案 0 :(得分:9)

这些消息表明应用程序正在花费more than 98% of its time收集垃圾。

我怀疑Scala会产生很多短命的物体,这就是造成过多GC的原因。您可以通过将-verbosegc命令行开关添加到java来验证GC性能。

Java 1.5+服务器VM上的default max heap size是1 GB(或已安装内存的1/4,以较少者为准),这应该足以满足您的需要,但您可能希望将新一代增加到看看这是否能提高你的表现。在Oracle VM上,使用-Xmn选项完成此操作。尝试设置以下环境变量:

$JAVA_OPTS=-server -Xmx1024m -Xms1024m -Xmn2m -verbosegc -XX:+PrintGCDetails

并重新运行您的应用程序。

您还应该查看this tuning guide了解详情。

答案 1 :(得分:3)

请尝试使用Jerkson。 Jerkson使用下面的Jackson,它反复评分为JVM上速度最快,内存最多的JSON解析器。

我在生产中使用了Lift JSON和Jerkson,而且Jerkson的性能明显优于Lift(特别是在解析和生成大型JSON文档时)。