【问题标题】:Huge memory leak with libxml2使用 libxml2 的巨大内存泄漏
【发布时间】:2013-05-15 14:07:33
【问题描述】:

我正在用 libxml2 编写一个 XML 解析器。实际上,我完成了它,但是有一个非常烦人的记忆问题。该程序首先从我的数据库中获取一些链接,所有这些链接都指向一个 XML 文件。我使用 curl 来下载它们。过程很简单:我下载一个文件,然后解析它,等等……

问题似乎出在解析完成时。 Curl 下载下一个文件,但似乎之前的 XML 没有被释放,因为我猜 libxml2 会将它加载到 RAM 中。在解析最后一个 XML 时,我发现自己有大约 2.6GB 的泄漏(是的,其中一些文件真的很大......)而且我的机器只有 4GB 的 RAM。目前可以,但是以后会在数据库中添加更多链接,所以我现在必须修复它。

我的代码很基础:

xmlDocPtr doc;
doc = xmlParseFile("data.xml");

/* code to parse the file... */

xmlFreeDoc(doc);

我尝试使用:

xmlCleanupParser();

但文档说:“它不会释放任何与文档相关的内存。” (http://xmlsoft.org/html/libxml-parser.html#xmlCleanupParser)

所以,我的问题是:有人知道如何释放所有与文档相关的内存吗?

【问题讨论】:

  • 如果您将大文件加载到内存中,我不明白您为什么会对巨大的内存使用量感到如此惊讶。 libxml2 是许多重要软件系统使用的一段备受推崇的代码,我非常怀疑正确使用 libxml2 是否存在“巨大的内存泄漏”。
  • 你怎么知道有内存泄漏?也许你的测量有缺陷......请注意,内存统计数据可能很难正确解释。
  • 尝试在 valgrind 下运行它,它会报告未分配内存的分配位置。
  • @carlosdc:我对内存使用情况并不感到惊讶,我只是不知道如何释放所有这些无用的数据。内存使用量仅在下载完成时才会增加(因此,就在解析之前),之后它绝对是静态的。
  • @rodrigo:我可以看到使用 htop,在调用 xmlFreeDoc(doc) 后没有任何内容被释放,所以我想我在那里遗漏了一些东西。当解析完成时,因此,当下一次下载开始时,内存使用量保持不变。 xmlFreeDoc 和 xmlFreeParser 是唯一似乎对释放内存有所帮助的函数,但它们都没有释放我想要的东西。我阅读了很多文档,但找不到相关内容。

标签: c libxml2


【解决方案1】:

问题是您以错误的方式查看统计信息...

当程序启动时,它会从操作系统为堆分配一些内存。当它执行malloc(或类似函数)时,C 运行时会从该堆中获取切片,直到它用完。之后,它会自动向操作系统请求更多内存,可能每次都以更大的块为单位。当程序执行free 时,它将释放的内存标记为可用于进一步的mallocs,但它不会将内存返回给操作系统。

您可能认为这种行为是错误的,即程序正在泄漏,但事实并非如此:释放的内存被考虑在内,只是不在操作系统中,而是在应用程序的 C 库层中。对此的证明是,第二个 XML 文件的内存并没有添加到第一个文件中:只有当它是最大的文件时,它才会被注意到。

你也可能认为,如果这个内存不再被这个程序使用,它只是在那里被浪费了,它不能被其他进程使用。但事实并非如此:如果内存在一段时间内没有被触及而在其他地方需要它,操作系统虚拟内存管理器会将其换出并重用。

所以,我的猜测是实际上你没有问题。

PS:我刚才描述的并不总是正确的。尤其是许多 C 库对大小内存块进行了区分,并以不同的方式分配它们。

【讨论】:

  • 这真的很有趣,我不知道。谢谢你的解释。在用 valgrind 进行了几次测试之后,我可以说你是对的。再次感谢你:)
  • 好吧,也许你是对的,根本没有内存泄漏。但事实是内存使用量正在增长,最终当它达到几乎 95% 的可用系统内存时,程序就会崩溃。如何解决这个问题呢。我的代码和@Pwet 一样
  • @crooveck:这通常意味着以下之一:A)您没有在使用后释放内存(您正在泄漏),因为如果您释放了它,它将被重用并且您不会达到 95 %; B)您实际上需要所有内存(您没有泄漏),例如因为您将 8GB XML 文件读入内存,而您只有 4GB 的物理内存加上交换......这是行不通的。
  • 我的代码与@Pwet 显示的相同。但我循环运行它。每次使用 xmlParseFile() 后,我都会执行 xmlFreeDoc()。我的 XML 大约只有几 kB,但被读取了很多次。几个小时后,我的程序被操作系统杀死了。我可以在运行 Valgrind 和 Memwatch 后确认没有内存泄漏,但它仍然会增长到几乎 100% 的系统内存 - 在被杀死之前。
  • 那么我很好奇,为什么当我使用 malloc() 分配 1 gig 时...将所有零写入它...然后释放它...。它会将内存返回到操作系统,但 libxml 没有?
【解决方案2】:

在游戏后期,但今天才发现这篇文章。它也可能对其他读者有用。

如果您正在解析或生成大型文档,您可以考虑使用 XmlReader 和 XmlReader API。显着减少内存使用量,无论输入有多大,实际上几乎是恒定的使用量。

http://xmlsoft.org/html/libxml-xmlreader.html http://xmlsoft.org/html/libxml-xmlwriter.html

【讨论】:

    猜你喜欢
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-02
    • 2014-02-10
    • 1970-01-01
    相关资源
    最近更新 更多