Java 如何使用staxapi处理大型XML文件(9gb)

Java 如何使用staxapi处理大型XML文件(9gb),java,xml,io,stream,stax,Java,Xml,Io,Stream,Stax,在处理大文件时,我总是遇到堆内存问题 这是我的密码 XMLInputFactory inputFactory = XMLInputFactory.newInstance(); InputStream in = new FileInputStream(sourcePath); XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

在处理大文件时,我总是遇到堆内存问题

这是我的密码

            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            InputStream in = new FileInputStream(sourcePath);
            XMLEventReader eventReader =  inputFactory.createXMLEventReader(in);

            Map<String, Cmt> mapCmt = new ConcurrentHashMap<String, Cmt>();
            while (eventReader.hasNext()) {
                XMLEvent event = eventReader.nextEvent();
                if (event.isStartElement()) {
                //some processing and assigning value to map
                Cmt cmt = new Cmt();
                //get attributes
                cmt.setDetails(attribute.getValue());
                mapCmt.put(someKey,cmt);
                }
            }
XMLInputFactory inputFactory=XMLInputFactory.newInstance();
InputStream in=新文件InputStream(sourcePath);
XMLEventReader eventReader=inputFactory.createXMLEventReader(在中);
Map mapCmt=新的ConcurrentHashMap();
while(eventReader.hasNext()){
XMLEvent=eventReader.nextEvent();
if(event.isStartElement()){
//对地图的一些处理和赋值
Cmt Cmt=新的Cmt();
//获取属性
setDetails(attribute.getValue());
mapCmt.put(someKey,cmt);
}
}
一段时间后,我在迭代中遇到堆内存问题。 请帮我写优化的代码

注意:服务器有可用的3 GB堆空间。我无法增加服务器空间。 我使用以下参数执行--Xms1024m-Xmx3g

我的xml看起来像这样

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<DatosAbonados xmlns="http://www.cnmc.es/DatosAbonados">
    <DatosAbonado Operacion="1" FechaExtraccion="2015-10-08">
        <Titular>
            <PersonaJuridica DocIdentificacionJuridica="A84619488" RazonSocial="HERMANOS ROJAS" NombreComercial="PINTURAS ROJAS"/>
        </Titular>
        <Domicilio Escalera=" " Piso=" " Puerta=" " TipoVia="AVENIDA" NombreVia="MANOTERAS" NumeroCalle="10" Portal=" " CodigoPostal="28050" Poblacion="Madrid" Provincia="28"/>
        <NumeracionAbonado>
            <Rangos NumeroDesde="211188600" NumeroHasta="211188699" ConsentimientoGuias-Consulta="1" VentaDirecta-Publicidad="1" ModoPago="1">
                <Operador RazonSocial="11888 SERVICIO CONSULTA TELEFONICA S.A." DocIdentificacionJuridica="A83519389"/>
            </Rangos>
        </NumeracionAbonado>
    </DatosAbonado>
    <DatosAbonado Operacion="1" FechaExtraccion="2015-10-08">
        <Titular>
            <PersonaJuridica DocIdentificacionJuridica="A84619489" RazonSocial="HERMANOS RUBIO" NombreComercial="RUBIO PELUQUERIAS"/>
        </Titular>
        <Domicilio Escalera=" " Piso=" " Puerta=" " TipoVia="AVENIDA" NombreVia="BURGOS" NumeroCalle="18" Portal=" " CodigoPostal="28036" Poblacion="Madrid" Provincia="28"/>
        <NumeracionAbonado>
            <Rangos NumeroDesde="211186000" NumeroHasta="211186099" ConsentimientoGuias-Consulta="1" VentaDirecta-Publicidad="1" ModoPago="1">
                <Operador RazonSocial="11888 SERVICIO CONSULTA TELEFONICA S.A." DocIdentificacionJuridica="A83519389"/>
            </Rangos>
        </NumeracionAbonado>
    </DatosAbonado>
</DatosAbonados>

我的Cmt课程是:

public class Cmt {
    private List<DetailInfo> details;

    public List<DetailInfo> getDetails() {
        return details;
    }
    public void setDetails(DetailInfo detail) {
        if(details == null){
            details = new ArrayList<DetailInfo>();
        }
        this.details.add(detail);
    }
}
公共类Cmt{
私人名单详情;
公共列表getDetails(){
退货详情;
}
公共无效集合详细信息(详细信息详细信息){
如果(详细信息==null){
详细信息=新的ArrayList();
}
this.details.add(details);
}
}
实际上Cmt对象很少,但我有详细信息对象 每一个元素。如此大量的DetailInfo对象 创造

我的逻辑是:

if (startElement.getName().getLocalPart().equals("DatosAbonado")) {
                    detailInfo = new DetailInfo();

                    Iterator<Attribute> attributes = startElement.getAttributes();
                    while (attributes.hasNext()) {
                        Attribute attribute = attributes.next();
                         if(attribute.getName().toString().equals("Operacion")){
                            detailInfo.setOperacion(attribute.getValue());
                        }
                    }
                }
if (event.isEndElement()) {
                EndElement endElement = event.asEndElement();
                if (endElement.getName().getLocalPart().equals("DatosAbonado")) {
                    Cmt cmt = null;
                    if(mapCmt.keySet().contains(identificador)){
                        cmt = mapCmt.get(identificador);
                    } else{
                        cmt = new Cmt();
                    }
                    cmt.setDetails(detailInfo);
                    mapCmt.put(identificador, cmt);
}
}
if(startElement.getName().getLocalPart().equals(“DatosAbonado”)){
detailInfo=新的detailInfo();
迭代器属性=startElement.getAttributes();
while(attributes.hasNext()){
Attribute=attributes.next();
if(attribute.getName().toString().equals(“操作”)){
setOperation(attribute.getValue());
}
}
}
if(event.isEndElement()){
EndElement EndElement=event.asEndElement();
如果(endElement.getName().getLocalPart().equals(“DatosAbonado”)){
Cmt-Cmt=null;
if(mapCmt.keySet()包含(identificator)){
cmt=mapCmt.get(identificator);
}否则{
cmt=新的cmt();
}
cmt.setDetails(详细信息);
mapCmt.put(identificator,cmt);
}
}

问题的根源很可能是:

mapCmt.put(someKey, cmt);
您正在用大量的
Cmt
对象填充hashmap。您需要执行以下操作之一:

  • 立即处理数据,而不是将其保存在数据结构中
  • 将数据写入数据库,以便以后查询
  • 增加堆大小
  • 为您的数据找出一种“内存不足”的表示形式

不过,最后两种方法无法扩展。随着您增加输入文件的大小,您将需要越来越多的内存。。。直到你最终超过执行平台的内存容量。

达托萨博纳多确实是杀手。如果您有大量的'm,这将导致您的应用程序阻塞

这种方法根本无法扩展。正如Stephan C所指出的,您需要在DatosAbonnado到达时对其进行处理,而不是将其收集到容器中

由于这是我为其开发LDX+代码生成器的典型场景,因此我进行了以下步骤:

  • 使用以下方法从XML创建XML架构文件(因为您没有提供):
  • 使用LDX+生成代码
此代码生成器实际上使用SAX,生成的代码允许您:

  • 将complexElements序列化为Java对象
  • 配置如何在运行时处理1对多关系(如此处的关系)
我在这里上传了代码: 要查看代码,请导航到源文件夹。在那里你可以找到DatosAbonnados


这种方法确实可以很好地扩展(内存消耗是平的)

在这个过程中您创建了多少
Cmt
对象?可能太多了,无法放入可用内存…您没有显示所有内容:
属性从何而来?您在mapCmt中存储了多少个Cmt对象,它们有多大?另外,为每个start元素事件创建一个Cmt似乎很奇怪。@laune这里我写了一些伪代码。创建的Cmt对象很少,但Cmt对象包含为每个对象创建的另一个对象的列表。@wero这里我编写了一种伪代码。创建的Cmt对象非常少,但Cmt对象包含为每个元素创建的另一个对象的列表。如果您要发布有关DatosAbonado的确切详细信息,以及您在存储的列表元素中存储的内容,则可以提供建议。XML看起来非常冗余,即这两个
有很多共同点。这将导致巨大的内存浪费。即使是String.intern也可能会减少内存。创建的Cmt对象很少,但Cmt对象包含为每个对象创建的另一个对象的列表。请检查更新的问题。这不会实质性地改变我的诊断,或者可能的解决方案。我的下一个方法是你的第二点,因为我认为我没有其他选择。谢谢你的宝贵建议。@Bunty如果你有兴趣,请快速研究一下“ETL”和“数据仓库”。这基本上是两者结合的第一步;从源和“sta”中提取数据