Scala - 在本地范围内的大量文件上执行XML.loadFile时的高堆使用率

Sac*_*kar 5 scala heap-memory

我试图从大量的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

huy*_*hjl 2

我无法重现这种行为。我使用以下程序:

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 对象。