我试图从大量的xmls创建一个对象树.但是,当我在大约2000 xml文件(范围从100KB到200MB)上运行以下代码时(注意我已经注释掉了创建对象树的代码),我获得了8-9GB的大内存占用.我希望在下面的示例中内存占用量最小,因为代码不会保留任何引用,它只会创建Elem并将其抛弃.运行完整GC后,堆内存保持不变.
def addDir(dir: File) {
dir.listFiles.filter(file => file.getName.endsWith("xml.gz")).foreach { gzipFile =>
addGzipFile(gzipFile)
}
}
def addGzipFile(gzipFile: File) {
val is = new BufferedInputStream(new GZIPInputStream(new FileInputStream(gzipFile)))
val xml = XML.load(is)
// parse xml and create object tree
is.close()
}
Run Code Online (Sandbox Code Playgroud)
我的JVM选项是:-server -d64 -Xmx16G -Xss16M -XX:+ DoEscapeAnalysis -XX:+ UseCompressedOops
而jmap -histo的输出看起来像这样
num #instances #bytes class name ---------------------------------------------- 1: 67501390 1620033360 scala.collection.immutable.$colon$colon 2: 37249187 1254400536 [C 3: 37287806 1193209792 java.lang.String 4: 37200976 595215616 scala.xml.Text 5: 18600485 595215520 scala.xml.Elem 6: 3420921 82102104 scala.Tuple2 7: 213938 58213240 [I 8: 1140334 36490688 scala.collection.mutable.ListBuffer 9: 2280468 36487488 scala.runtime.ObjectRef 10: 1140213 36486816 scala.collection.Iterator$$anon$24 11: 1140210 36486720 scala.xml.parsing.FactoryAdapter$$anonfun$startElement$1 12: 1140210 27365040 scala.collection.immutable.Range$$anon$2 ... Total 213412869 5693850736
我无法重现这种行为。我使用以下程序:
import java.io._
import xml.XML
object XMLLoadHeap {
val filename = "test.xml"
def addFile() {
val is = new BufferedInputStream(new FileInputStream(filename))
val xml = XML.load(is)
is.close()
println(xml.label)
}
def createXMLFile() {
val out = new FileWriter(filename)
out.write("<foo>\n")
(1 to 100000) foreach (i => out.write(" <bar baz=\"boom\"/>\n"))
out.write("</foo>\n")
out.close()
}
def main(args:Array[String]) {
println("XMLLoadHeap")
createXMLFile()
(1 to args(0).toInt) foreach { i =>
println("processing " + i)
addFile()
}
}
}
Run Code Online (Sandbox Code Playgroud)
我使用以下选项运行它:-Xmx128m -XX:+HeapDumpOnOutOfMemoryError -verbose:gc它基本上看起来可以无限期地运行。
您可以尝试看看仅使用最大的 XML 文件时是否会出现此情况。问题可能不在于处理许多文件,而在于处理最大的文件。当在 64 位机器上使用虚拟 200MB XML 文件进行测试时,我发现我需要大约 3G 的内存。如果是这种情况,您可能需要使用拉解析器。请参阅XMLEventReader。
除此之外,假设您不创建对象树,您可以使用MAT-Xmx4G -XX:+HeapDumpOnOutOfMemoryError等工具来使用并分析堆转储。4GB 应该足以解析最大的 XML 文件,并且当您收到内存不足错误时,可能已经分配了足够的对象来查明哪个对象正在阻止 GC。最有可能的是,该对象保存着各种已解析的 XML 对象。