我们的应用程序需要以XML格式(几个文件)呈现客户端数据,并将其解析为我们的通用XML格式(带有架构的单个文件)。为此,我们使用apache的XMLBeans数据绑定框架。下面简要介绍这个过程的步骤。
首先,我们将原始java.io.File对象指向磁盘上的客户端XML文件,并将它们加载到集合中。然后,我们遍历此集合,为每个文件创建一个apache.xmlbeans.XmlObject。在将所有文件解析为XmlObjects之后,我们创建了4个集合,其中包含我们感兴趣的XML文档中的各个对象(很明显,这些不是手工制作的对象,但我只能将其描述为' proxy& #39;由apache的XMLBeans框架创建的对象)。最后一步,我们迭代这些集合以生成我们的 XML文档(在内存中),然后将其保存到磁盘。
对于大多数用例,此过程运行正常,并且在给定' -Xmx1500m'时可以轻松地在JVM中运行。命令行参数。但是,当我们获得大型数据集时会出现问题。由客户。在这种情况下,大型的123Mb客户端XML分布在7个文件中。这样的数据集导致我们的代码内集合中填充了大约40,000个上述代理对象'。在这些情况下,内存使用只是通过屋顶。 我没有得到任何outofmemory异常程序只是挂起,直到垃圾收集发生,释放少量内存,然后程序继续,耗尽这个新空间并重复循环。这些解析会话目前需要4-5个小时。我们的目标是在一小时内将其降低。
需要注意的是,将客户端xml转换为xml所需的计算需要所有xml数据进行交叉引用。因此,我们无法实现顺序解析模型或将此流程批处理为较小的块。
到目前为止我尝试了什么
不是将所有123Mb的客户端xml保存在内存中,而是在每次请求数据时,加载文件,查找数据并释放对这些对象的引用。这似乎可以减少在此过程中消耗的内存量,但是您可以想象,常量I / O所花费的时间消除了减少内存占用的好处。
我怀疑一个问题是我们持有一个价值123Mb的XML文件的XmlObject []以及从这些文件中获取的对象集合(使用xpath查询)。为了解决这个问题,我改变了逻辑,以便不是查询这些集合,而是直接查询文档。这里的想法是,在任何时候都不存在4个大量的列表,其中包含10个对象中的10个,只是XmlObjects的大集合。这似乎没有任何区别,在某些情况下,甚至会增加内存占用。
现在抓住吸管,我认为在写入磁盘之前我们用来在内存中构建我们的 xml的XmlObject变得太大而无法与所有客户端数据一起维护。但是,对此对象执行一些sizeOf查询显示,在此最大的对象上,此对象小于10Kb。在阅读了XmlBeans如何管理大型DOM对象之后,它似乎使用了某种形式的缓冲编写器,因此很好地管理了这个对象。
所以现在我没有想法;不能使用SAX方法而不是内存密集型DOM方法,因为我们的应用程序中任何时候都需要100%的客户端数据,在我们绝对需要它之前不能阻止请求这些数据,因为转换过程需要大量的循环和磁盘I / O时间不值得保存的内存空间,我似乎无法构造我们的逻辑,以减少内部Java集合占用的空间量。我在这里运气不好吗?我必须接受,如果我想将123Mb的xml数据解析成我们的Xml格式,我无法用1500m的内存分配吗?虽然123Mb是我们域中的一个大型数据集,但我无法想象其他人从来没有必须同时使用Gb的数据做类似的事情。
其他可能很重要的信息
答案 0 :(得分:3)
我采取的方法是对文件进行两次传递,在两种情况下都使用SAX。
第一遍将解析计算中所需的“交叉引用”数据到自定义对象中并存储它们Map
。如果“交叉引用”数据很大,那么请查看使用分布式缓存(如果您从Map
开始,Coherence是自然适合的。)
第二遍将解析文件,检索“交叉引用”数据以根据需要执行计算,然后使用javax.xml.stream
API编写输出XML。