我有一些大于可用内存的 XML 文件,以及一个大型(!)代码库,假设它可以使用 DOM 结构对该文件进行操作。但是,一些用户报告了大输入大小的 OutOfMemoryException ;并且 XML 大于 32 位处理器上可用的地址空间。
是否有可以处理这种情况的 DOM 实现,并且只在必要时“水合”子对象,以实现对大量 XML 文件的合理内存使用?
MS XmlTeam 在两篇文章中概述了一个很好的解决方案,用于获得 linq2xml 的好处,但流式传输文件而不是加载整个内容。经过许多死胡同和死胡同,这是我从数据库转储中读取 >10GB xml 文件时确定的解决方案。
DOM对象模型依赖于将所有数据加载到内存中的事实。即使你会发现一个实现延迟加载延迟的东西,如果DOM api 用户遍历整个DOM树,你仍然会耗尽内存。
实际上,当您执行XMemorySavingXDocument
.Load("big.xml")` 时会节省内存,但第一个 XPath 或 LINQ 查询仍会导致OutOfMemoryException。如果任何查询确实遍历了完整的 DOM 树,则这是正确的。如果你能确保永远不会出现这种情况,那么你就可以摆脱这种懒惰的 DOM 树。
我不知道任何这样的实现,但我怀疑无论如何它会对你的情况有所帮助。正如你所说,大量的 DOM Api 用户将通过 DOM 树接触所有节点,并且通过这样的解决方案,你会在几毫秒后得到 OutOfMemoryException。
XML DOM 对象模型确实将 xml 文件“解压缩”为内存中的表示形式,它消耗的内存 (x64) 比原始文件多 7 倍。对于 32 位,它仍然是大约 3.5 倍。
XML DOM 模型如此臃肿的原因是每个 dom 节点都知道它的子节点、父节点和属性。这是每个 DOM 节点的对象引用,确实会花费你很多。
托管类对象每个实例至少消耗 12/24 字节。由于每个节点指针确实会在总内存消耗中增加 4/8 字节(x86,x64),因此使用大的 xml 文件会很快耗尽内存。有关 .NET 对象大小的更多信息,请参阅本文。
由于 DOM 对于大型 XML 文件不是一个好主意,但您当前的架构需要 DOM,我担心您需要将 DOM 抽象出来,并用一个可以提取(并可能修改)您感兴趣的内容的 API 替换它。在一个大型组织,您可以将这个主题提交给建筑师,并将其作为一个必须优先考虑的重大重新设计来展示。
如果您更幸运地得到架构师和管理层的承诺,那么您从未去过的国家的一些外包程序员可以让他们的下一个大型积压项目开始工作;-)。
为了给你一些数字,我确实创建了一个包含 100 万个整数的文件,数据格式对性能的影响有多大。我确实使用了 3 种不同的数据格式
然后我确实在 64 位进程中读取了它们
除了 XDocument.Load 导致 1.2 GB 的内存峰值外,内存消耗持平在 ~ 200 MB。您的性能目标可能不同,但我会首先通过流式 XmlReader 将 Xml 内容转换为可以更快加载的二进制格式。
这不是最佳解决方案,但在过去,我将 XML 文件作为字符串读取,并使用正则表达式将部分分解为它们自己的 DOM 对象。
也许您也可以使用 XPath?(https://developer.mozilla.org/en-US/docs/Using_XPath)