2010-10-02 17 views
5

Tôi đang cố tạo một cây đối tượng từ số lượng lớn xml. Tuy nhiên, khi tôi chạy đoạn mã sau trên khoảng 2000 tệp xml (dao động từ 100KB đến 200MB) (lưu ý rằng tôi đã nhận xét ra mã tạo ra cây đối tượng), tôi nhận được một khoảng trống bộ nhớ lớn là 8-9GB. Tôi hy vọng rằng dấu vết bộ nhớ là tối thiểu trong ví dụ sau bởi vì mã không doen't giữ bất kỳ tài liệu tham khảo, nó justs tạo ra Elem và ném nó đi. Bộ nhớ heap vẫn giữ nguyên sau khi chạy GC đầy đủ.Scala - Sử dụng đống cao khi thực hiện XML.loadFile trên số lượng lớn tệp trong phạm vi địa phương

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

tùy chọn JVM của tôi là: -server -d64 -Xmx16G -Xss16M -XX: + DoEscapeAnalysis -XX: + UseCompressedOops

Và đầu ra của jmap -histo trông như thế này

 
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 

Trả lời

2

Tôi không thể tái tạo hành vi này. Tôi sử dụng chương trình sau đây:

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

} 

tôi chạy nó với các tùy chọn sau: -Xmx128m -XX:+HeapDumpOnOutOfMemoryError -verbose:gc và nó về cơ bản trông giống như nó có thể chạy vô thời hạn.

Bạn có thể thử xem nó có thực hiện điều này khi chỉ sử dụng tệp XML lớn nhất của bạn hay không. Có thể vấn đề không phải là xử lý nhiều tệp, nhưng chỉ xử lý tệp lớn nhất. Khi thử nghiệm ở đây với một tập tin XML 200MB giả trên một máy 64 bit, tôi thấy rằng tôi cần khoảng 3G bộ nhớ. Nếu đúng như vậy, bạn có thể cần phải sử dụng trình phân tích cú pháp kéo. Xem XMLEventReader.

Ngoài ra, giả sử bạn không tạo cây đối tượng, bạn có thể sử dụng -Xmx4G -XX:+HeapDumpOnOutOfMemoryError và sau đó phân tích vùng lưu trữ đống bằng công cụ như MAT. 4GB nên đủ để phân tích cú pháp tệp XML lớn nhất và vào thời điểm bạn nhận được lỗi bộ nhớ, có thể có đủ đối tượng được phân bổ để xác định đối tượng nào đang ngăn GC. Nhiều khả năng đó sẽ là một đối tượng đang nắm giữ trên các đối tượng XML được phân tích cú pháp khác nhau.

+0

Chạy chương trình (từ bảng điều khiển scala, để vm vẫn hoạt động) đối với tệp xml lớn nhất (438MB). Việc sử dụng đống không có vẻ là vấn đề –

+0

Chạy chương trình (từ bảng điều khiển scala, để vm vẫn còn sống) cho tệp xml lớn nhất (438MB). Lấy bản tóm tắt đống sau khi tải tệp và chạy toàn bộ gc. Việc sử dụng heap không có vẻ là vấn đề vì chỉ có 111MB thế hệ cũ (và 0 thế hệ trẻ) đang được sử dụng. Tuy nhiên, đầu ra của lệnh 'top' hiển thị kích thước còn lại (RES) là 4,8GB. –

+0

Mặt khác, chạy với tốc độ heap 32 bit (3GB): java.lang.OutOfMemoryError: Giới hạn trên GC vượt quá tại scala.xml.parsing.FactoryAdapter.startElement (FactoryAdapter.scala: 136) tại com.sun.org .apache.xerces.internal.parsers.AbstractSAXParser.startElement (AbstractSAXParser.java WEBC01) tại com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement (XMLDocumentFragmentScannerImpl.java:1363) at com.sun .org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl $ FragmentContentDriver.next ... –

Các vấn đề liên quan