【问题标题】:Unmarshalling Large Xml files in Java在 Java 中解组大型 Xml 文件
【发布时间】:2018-11-07 00:50:39
【问题描述】:

我正在尝试将大小约为 6Gb 的大型 xml 文件解组为 java 对象。下面是我用来解析大文件的实现。它仅适用于 20Gb 堆空间。我想进一步减少内存占用。

XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("abc.xml"));
xsr.nextTag();
long addEntity = 0;
long unmarshalEntity = 0;

JAXBContext jc = JAXBContext.newInstance(XYZ.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
while(xsr.nextTag() == XMLStreamConstants.START_ELEMENT) {
    long start1 = System.currentTimeMillis();
    XYZ sample = (XYZ) unmarshaller.unmarshal(xsr);
}

它不断抛出原因:java.lang.OutOfMemoryError:任何较小的堆都超出了 GC 开销限制。如果我解析整个文件,我将拥有 330 万个 XYZ 对象。那么有没有一种方法可以让我将这些对象保存在内存中,因为我需要对这些对象进行一些后期处理,因为后期处理依赖于多个 XYZ 对象。

【问题讨论】:

  • 嗯......当您尝试将 6GB XML 文件解组为对象时,您期望什么?解决方案是,不要一次阅读所有内容。您已经创建了一个 XML 流阅读器。使用它。
  • 您是否同时需要所有对象?否则,您可以分块进行后期处理。或者将它们交换为具有正常序列化的二进制文件,然后一次串行处理该文件一个对象。我认为您的问题与 XML 无关,代码看起来不错。您可以通过不抓住对象来验证。如果问题是您需要 330 万个对象并且无法为它们分配内存,那么您就卡住了。
  • 如何查找所有 3.3M 对象的大小以识别其超出堆大小?
  • 您可以use JAXB with StAX 以类似流的方式处理对象。

标签: java xml-parsing jaxb


【解决方案1】:

按照您的解析方式,XML 的所有数据最终都将转换为 Java 类层次结构,并最终存储在内存中。

为避免大文件出现内存问题,您可以:

  • 直接使用事件驱动的 SAX 解析器,几乎不消耗内存。
  • 对 JAXB 使用部分解组

这将对如何处理 XML 数据施加一些限制,因为它们永远不会一次全部可用。 如果后处理发生在一些合理大小的 XML 块中,这不是问题,因为您可以在内存中执行此操作。 如果需要对整个 XML 进行后处理,一种选择是将数据加载到数据库中并在那里进行后处理。

【讨论】:

  • 引起:com.sun.istack.SAXParseException2;行号:119576912;是抛出的异常.. 所以我假设它在内部使用 stax
  • JAXB (JSR-222) 可以在内部使用 DOM / SAX 解析器,但它们最终会被转换为 JAVA 类层次结构 -> 最终都在内存中。您必须直接使用 SAX 解析器以避免内存消耗问题。
  • 您可以轻松地将 JAXB 与 StAX 结合使用。
  • @butchyyyy 但它们最终被转换为 JAVA 类层次结构 -> 最终都在内存中 - 这是一个谬论。是的,JAXB 将 XML 转换为对象,但是,它们不必一次性全部进入内存。
【解决方案2】:

如果有人需要一个具体的例子来说明如何通过 StAX 使用 JAXB:

XMLInputFactory xif = XMLInputFactory.newInstance()
XMLStreamReader reader = xif.createXMLEventReader(new StreamSource("abc.xml"))
JAXBContext jc = JAXBContext.newInstance(XYZ.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();

while (!reader.peek().isEndDocument) {
  if (reader.peek().isStartElement && 
        reader.peek().asStartElement().getName().getLocalPart().equals("xyz")) {
    XYZ sample = (XYZ) unmarshaller.unmarshal(reader);
    //do thing with sample
  }
  reader.nextEvent()
}
reader.close()

【讨论】:

    猜你喜欢
    • 2013-02-14
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 2015-08-12
    • 2019-02-18
    • 1970-01-01
    • 2019-09-23
    相关资源
    最近更新 更多