【问题标题】:Memory management while loading huge XML files加载大型 XML 文件时的内存管理
【发布时间】:2009-03-24 10:22:53
【问题描述】:

我们有一个从 XML 导入对象的应用程序。 XML 大约为 15 GB。应用程序总是开始耗尽内存。我们试图在操作之间释放内存,但这会导致性能下降。即完成导入操作需要更多时间。 CPU利用率达到100%

应用程序是用 C++ 编写的。

频繁调用free()会导致性能问题吗?


来自 OP 的评论:expat 中使用的解析器,这是一个 SAX 解析器,占用空间非常小,可自定义内存管理。

【问题讨论】:

  • 您使用的是哪个解析器.. MSXML?
  • 这是一个 15GB 的 XML 文件吗?您期望生成的对象使用多少空间?您是导入所有对象还是仅导入一个选择?您在 64 位平台上吗?
  • 是的,我在 64 位平台上。它是一个 15 GB 的文件
  • 您需要向我们提供有关您的应用程序架构的更多详细信息 - 例如,您使用什么数据结构?

标签: c++ xml memory memory-management


【解决方案1】:

使用SAX 解析器而不是DOM 解析器。

【讨论】:

    【解决方案2】:

    您是否尝试过恢复内存和类,而不是释放和重新分配它?恒定的分配/解除分配周期,尤其是与小的(小于 4096 字节)数据碎片相结合的情况下,可能会导致严重的性能问题和内存地址空间碎片。

    【讨论】:

    • 另外 - 他应该使用 valgrind 和 massif 工具来查看哪些类是最佳候选者。
    【解决方案3】:

    在这些令人讨厌的负载之一期间分析应用程序,以查看其大部分时间都花在了哪里。

    我相信free() 有时会很昂贵,但这当然很大程度上取决于平台的实现。

    另外,你没有说太多关于加载对象的生命周期;如果 XML 为 15 GB,一旦标记被解析并丢弃,每个“对象”会保留多少?

    以流方式处理这种大小的输入文档听起来很明智,即不尝试一次性加载和构建整个 XML 解析树的 DOM 方法。

    【讨论】:

      【解决方案4】:

      如果您想尽量减少内存使用量,请查看How to read the XML data from a file by using Visual C++。

      【讨论】:

      • 您是否有任何证据表明导入 .net 框架会比使用内存占用很小的 Expat 带来净收益?
      • @Pete Kirkham:对不起,我没有。我只在回答后阅读了 Expat 位。
      【解决方案5】:

      通常有用的一件事是使用轻量级的低开销内存池。如果将其与“帧”分配方法结合使用(在完成数据处理之前忽略任何删除/释放),您可以获得快得离谱的东西。

      我们最近为一个嵌入式系统做了这个,主要是出于性能原因,但它也节省了很多内存。

      诀窍基本上是分配一个大块——比我们需要的稍微大一点(如果你愿意,你可以分配一个块链)——然后继续返回一个“当前”指针(通过 allocSize ,在我们的例子中,每次向上取整到最大对齐要求 4)。这将我们每个分配的开销从大约 52-60 字节减少到

      如果您对帧分配足够聪明,则可以节省大量空间和时间。它可能无法让您一直达到 15GiB,但值得看看您真正拥有多少空间开销......我对基于 DOM 的系统的经验是它们使用大量的小型分配,每个分配都具有相对较高的开销。

      (如果你有虚拟内存,一个大的“块”甚至可能不会造成太大的伤害,如果你在任何给定时间的访问都是本地页面或三个页面......)

      显然,从长远来看,您必须保留实际需要的内存,但解析器的“临时内存”通过这种方式变得更有效率。

      【讨论】:

      • expat 解析器是否在内部分配小块内存,然后释放它?我有 2 GB 的虚拟内存。多大的块才足够公平?
      • 我不确定 expat,尤其是在 SAX 模式下。要找出最简单的方法是重写分配器以打印它正在分配和释放的内容,然后解析一个小页面。 (或者收集统计数据然后打印出来。)一旦你掌握了这些信息,你就可以对区块做出明智的决定。
      【解决方案6】:

      我们试图在操作之间释放内存,但这会导致性能下降。

      频繁调用free()会不会导致性能问题?

      根据提供的证据,是的。

      既然您已经在使用 expat,一个 SAX 解析器,那么您 freeing 到底是什么?如果你可以释放它,为什么你首先要在循环中mallocing 它?

      【讨论】:

      • 其实有 memcpy(x,y,len) 的用法。所以我们决定在 memcpy 操作之后 free(y) 。我们还尝试使用 memmove 而不是 memcpy
      • 你到底在释放什么?我在 xpat 中唯一知道的是您正在从属性或字符数据中复制值,在这种情况下 y 由解析器管理,而 x 是您要复制到的内容,因此在任何情况下您都不会释放 x 或 y .
      【解决方案7】:

      也许,它应该说分析器。

      别忘了堆的工作是单线程的。我的意思是,如果您的线程的展位将按时分配/释放内存,那么其中一个线程将在第一次完成时等待。

      如果您为相同的对象分配和释放内存,您可以创建该对象的池并执行一次分配/释放。

      【讨论】:

        【解决方案8】:

        尝试找到一种方法来分析您的代码。

        如果您没有分析器,请尝试组织您的工作,以便您只有几个 free() 命令(而不是您建议的多个)。

        必须在内存消耗和时间效率之间找到适当的平衡点是很常见的。

        【讨论】:

          【解决方案9】:

          我自己没试过,但是你听说过XMLLite吗,有一个MSDN artical介绍它。它由 MS Office 内部使用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-05-02
            • 2019-02-19
            • 2011-06-14
            • 2018-04-20
            • 2016-01-17
            • 1970-01-01
            • 2014-03-21
            相关资源
            最近更新 更多