是否存在任何在解析时未加载整个文件的DOM实现?

时间:2012-08-09 20:19:05

标签: c# xml dom

我有一些比可用内存大的XML文件,以及一个大的(!)代码库,它假设它可以使用DOM结构在该文件上运行。但是,有些用户在大输入大小上报告了OutOfMemoryException;并且XML大于32位处理器上可用的地址空间。

是否有一个可以处理这种情况的DOM实现,并且只为了实现合理的内存使用和大量的XML文件而“必要时”保存子对象?

3 个答案:

答案 0 :(得分:2)

MS XmlTeam有一个great solution outlined in a two part post可以获得linq2xml的好处,但是流式传输文件而不是加载整个文件。在许多盲目的小巷和死胡同之后,这是我从数据库转储中读取> 10GB xml文件时解决的解决方案。

答案 1 :(得分:1)

DOM 对象模型依赖于将所有数据加载到内存中的事实。即使您发现延迟加载延迟的实现,如果 DOM api用户遍历整个 DOM 树,您仍然会耗尽内存。

实际上,当你执行XMemorySavingXDocument时,你会节省内存。加载(“big.xml”)`但第一个XPath或LINQ查询仍然会导致 OutOfMemoryException 。如果任何查询遍历完整的DOM树,则为true。如果你能确保永远不会出现这种情况,你就可以使用这种懒惰的DOM树。

我不知道任何此类实施,但我怀疑它无论如何都会对你的情况有所帮助。正如你所说的那样,大量的DOM Api用户将在涉及所有节点的DOM树中跋涉,并且只有几毫秒后才能通过这样的解决方案获得OutOfMemoryException。

XML DOM对象模型将xml文件“解压缩”到内存表示中,该内存表示比原始文件消耗大约7倍的内存(x64)。对于32位,它仍然是3.5倍。

XML DOM模型如此臃肿的原因是每个dom节点都知道它的子,父和属性。这是每个DOM节点的对象引用,它们会花费你很多。

托管类对象每个实例至少消耗12/24个字节。由于每个节点指针确实将额外的4/8字节(x86,x64)添加到总内存消耗中,因此使用大型xml文件可以非常快速地耗尽内存。有关.NET对象大小的更多信息,请参阅此article

由于DOM对于大型XML文件不是一个好主意,但是您当前的架构需要DOM,我担心您需要抽象DOM并将其替换为提取(并可能修改)您感兴趣的内容的API。在一个大型组织中,您可以将这个主题提交给建筑师,并将其作为必须具有prio的重大重新设计。

如果你更幸运的是得到了建筑师和管理层的承诺,那么一些外包的程序员在你从来没有得到他们的下一个大的积压项目工作的国家;-)。

为了给你一些数字格式确实影响性能的数字,我创建了一个包含100万个整数的文件。我确实使用了3种不同的数据格式

  • 二进制40 MB
  • ASCII文本文件80 MB(ddd \ r \ ndddd \ r \ n ... n)
  • Xml文件170 MB( 1 \ r \ n 2 ....)

然后我在64位进程中读取了它们

  • 0,1s通过内存映射文件的二进制文件
  • 0,5s BinaryReader
  • 2,5s文本文件
  • 5,3s XmlReader(流媒体)
  • 8,6s XDocument.Load

除了XDocument.Load之外,内存消耗平稳在200 MB左右,这确实导致1.2 GB的内存峰值。您的性能目标可能会有所不同,但我会首先通过流式XmlReader将Xml内容转换为二进制格式,这种格式可以加载得更快。

答案 2 :(得分:0)

这不是一个最佳解决方案,但在过去,我已经将XML文件作为字符串读入,并使用正则表达式将部分分解为自己的DOM对象。

也许你也可以使用XPath? (https://developer.mozilla.org/en-US/docs/Using_XPath)