2010-10-02 11 views
5

Sto provando a creare un albero di oggetti da un numero elevato di xmls. Tuttavia, quando eseguo il seguente codice su circa 2000 file xml (da 100 KB a 200 MB) (si noti che ho commentato il codice che crea l'albero degli oggetti), ottengo un ingombro di memoria di 8-9 GB. Mi aspetto che l'impronta della memoria sia minima nell'esempio seguente, poiché il codice non mantiene alcun riferimento, ma crea Elem e lo getta via. La memoria heap rimane la stessa dopo aver eseguito il GC completo.Scala: utilizzo elevato dell'heap quando eseguito XML.loadFile su un numero elevato di file nell'ambito locale

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() 
} 

mie opzioni JVM sono: -server -d64 -Xmx16G -Xss16M -XX: + DoEscapeAnalysis -XX: + UseCompressedOops

e l'uscita del jmap -histo sembra questo

 
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 

risposta

2

Non riesco a riprodurre questo comportamento. Io uso il seguente programma:

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() 
    } 
    } 

} 

ho eseguito con le seguenti opzioni: -Xmx128m -XX:+HeapDumpOnOutOfMemoryError -verbose:gc e sembra praticamente come può funzionare a tempo indeterminato.

Si può provare a vedere se lo fa quando si utilizza solo il file XML più grande. È possibile che il problema non riguardi l'elaborazione di molti file, ma solo l'elaborazione del file più grande. Quando eseguo il test qui con un file XML fittizio da 200 MB su una macchina a 64 bit, vedo che ho bisogno di circa 3G di memoria. In tal caso, potrebbe essere necessario utilizzare un parser di pull. Vedi XMLEventReader.

Oltre a ciò, presupponendo di non creare l'albero degli oggetti, è possibile utilizzare -Xmx4G -XX:+HeapDumpOnOutOfMemoryError e quindi analizzare il dump dell'heap con uno strumento come MAT. 4 GB dovrebbero essere sufficienti per analizzare il file XML più grande e quando si verifica un errore di memoria insufficiente, potrebbero esserci abbastanza oggetti allocati per individuare quale oggetto sta impedendo il GC. Molto probabilmente questo sarà un oggetto che si aggrappa ai vari oggetti XML analizzati.

+0

Ha eseguito il programma (dalla console di scala, in modo che il vm rimanga attivo) per il singolo file xml più grande (438 MB). L'utilizzo dell'heap non sembra essere il problema –

+0

Ha eseguito il programma (dalla console di scala, in modo che il vm rimanga attivo) per il singolo file xml più grande (438 MB). Preso il sommario dell'heap dopo aver caricato il file ed eseguito gc completo. L'utilizzo dell'heap non sembra essere il problema poiché vengono utilizzati solo 111 MB di vecchia generazione (e 0 di nuova generazione). Tuttavia, l'output del comando 'top' mostra la dimensione residua (RES) di 4,8 GB. –

+0

D'altra parte, l'esecuzione con heap a 32 bit (3 GB) genera: java.lang.OutOfMemoryError: limite di overhead GC superato su scala.xml.parsing.FactoryAdapter.startElement (FactoryAdapter.scala: 136) su com.sun.org .apache.xerces.internal.parsers.AbstractSAXParser.startElement (AbstractSAXParser.java:501) in com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement (XMLDocumentFragmentScannerImpl.java:1363) in com.sun .org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl $ FragmentContentDriver.next ... –

Problemi correlati