【问题标题】:My program is slowing down over time and i have no idea why. Memory leak?我的程序随着时间的推移变慢了,我不知道为什么。内存泄漏?
【发布时间】:2019-11-14 23:59:44
【问题描述】:

我正在开发一个程序,它充当一个非常简单的投票系统,它从文件中读取数字,将文件中的数字转换为 unsigned int 类型。

以下是 txt 文件中数据的示例:

1 34 2 50 23 12
1 30 5 17
5
30 2 3 22
23 45

每一行是一个人的投票,每行上的数字是这个人的候选人偏好,左边是第一偏好,右边是最后偏好。

一旦从文件中读取所有数据,它就会进入一个无限循环,其中每一轮(迭代)它都会计算剩余的候选人(即淘汰得票最少的候选人)。当找到具有多数票的候选人时,程序以代码 0 退出。

我的问题是使用 g++ 编译器,大约在 40 左右,程序开始变慢,我假设这是因为内存泄漏,但是我不知道它可能在程序中的哪个位置泄漏.

This is what I get when debugging the program through Deleaker.

注意:谢谢大家的帮助。但是,尽管我不想这样做,但由于某些原因,我需要编辑此处发布的代码。我不会删除帖子,以防有人能以某种方式找到答案。希望您能理解,谢谢。

【问题讨论】:

  • 这是调试器和/或分析器的工作。使用-Og -g 选项编译程序后,分析器(例如perf)会告诉您大部分时间都花在了哪里。调试器(例如gdb)允许您在有问题的部分中断程序并逐个执行指令,以查看与您预期不同的情况。这不太可能是内存泄漏问题(您没有使用new 或类似的东西)。更有可能是您的算法具有意外的大运行时间。
  • 还要确保在不进行调试时,您使用-O2-O3 优化标志到g++
  • 我没有看到任何暗示“内存泄漏”的迹象。一切都使用容器。在任何会导致泄漏的地方都没有看到new。显示的代码偏大,需要分析;但根据给定的描述,它更有可能是一个糟糕或低效的算法。
  • 您的代码中有很多分配。大量复制大型对象。
  • 我刚刚意识到,通过图像,您在 Windows 上。在这种情况下,我对探查器和调试器的建议不适用(即 perfgdb 不适用于 Windows)。我不知道 Windows 上常用的分析器和调试器是什么。

标签: c++ performance memory-leaks


【解决方案1】:

我在这里做一些猜测,但就算法的时间复杂度而言,

while (p != vote_collection.end())  {
    //...
    if (p->spent()) {
        p = vote_collection.erase(p);
    }
 }

是有问题的,因为vote_collection 是一个向量。假设N 是该容器的大小,即投票数。当p->spent() 为真时(在以后的迭代中更有可能发生),那么您将删除p。在最坏的情况下,从向量中擦除元素在N 中具有线性时间复杂度(在开始擦除时,您可能会在从头到尾迭代向量时这样做。)因为这将发生在许多人身上他投票,这个循环在N 中具有二次时间复杂度。如果输入变量可能很大,您总是希望避免二次复杂性。

出现这种情况的原因是向量将元素连续存储在内存中。当您擦除一个元素时,擦除后的所有其他元素必须移动一个元素以缩小间隙。这需要在擦除的元素接近开头时移动几乎整个向量。

您可以简单地将所有已用票留在向量中,并确保ranked_candidates 跳过已用票,而不是使用当前方法。

【讨论】:

  • 啊,我明白了。我会实施您的建议,并就它的工作原理与您联系!
  • 好消息!这似乎奏效了!后面几轮不再放缓。我只有一个小问题,例如,即使其中大约 4000 个条目是空的,它仍然会将投票数读取为 10000。这会导致计算出现问题,因为我根据 vote_collection 向量的大小来确定哪个候选人拥有多数票。有没有办法让 vote_collection.size() 排除空的整体?或者我可以在我做计数的地方保留一个计数 - 或 ++ 根据当前元素在 .discard() 之后是否为空?
  • @DWO No std::vector 确实提供了这样的选项,但是您可以按照您的说法自己使用计数,或者您可以编写一个迭代向量并计算未花费条目的函数,或者您可以查看vote_collection 的其他容器。例如std::list<vote>,尽管这通常具有糟糕的内存访问模式。您也可以使用std::vector 解决问题,方法是将需要删除的投票替换为向量中的最后一票,然后将向量的大小减一,因为您对投票的顺序并不感兴趣矢量(我认为)。
  • 在向量顺序方面,需要按照对中的值降序排列。但是,显然,该值不像键(候选)那样是唯一的。所以你的最后一个建议不起作用,因为我需要再次按降序对向量进行排序。
  • @DWO 我说的是vote 对象在vote_collection 中的顺序。您只需在ranked_candidates 中本地形成<candidate, int> 对,并在vote_collection 中形成计数vote 对象的顺序无关紧要。
猜你喜欢
  • 2014-12-11
  • 1970-01-01
  • 2019-01-25
  • 1970-01-01
  • 1970-01-01
  • 2012-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多