如何追踪Valgrind未检测到的内存泄漏?

8
我有一个程序能够从socket接收数据,进行质量控制和其他条件处理,然后将其写入命名管道。我对它运行了valgrind并修复了原本存在的所有内存泄漏。然后我在一个系统上创建了一个“演示”环境,其中有32个实例运行该程序,每个实例都被提供唯一的数据并输出到自己的管道。我们进行了测试,一切看起来都很好。然后我试图通过增加发送数据的速率来进行压力测试,最初情况看起来不错...但我的程序持续消耗更多的内存直到没有资源可用。
我转向valgrind,并使用leak-check=full在每个程序内部运行相同的设置。发生了一些奇怪的事情。首先,内存确实泄漏了,但只到每个程序已经消耗了我的内存的0.9%(以前最大的内存占用量为6%)。使用valgrind时,程序的CPU成本飙升,我的CPU利用率达到了100%,负载平均值很高,因此可能是可用CPU不足导致程序运行缓慢,使泄漏需要太长时间才能显现。当我尝试停止这些程序时,valgrind并没有显示任何直接的内存泄漏,它显示了一些潜在的内存泄漏,但我检查过它们并不认为它们代表实际的内存泄漏;而且可能的内存泄漏只显示为几KB,而程序却消耗了超过100MB。valgrind报告的可达(未泄露)内存也是在KB范围内,因此valgrind似乎认为我的程序消耗的内存只是Top所显示的使用量的一小部分。
我进行了一些其他测试,并得到了奇怪的结果。单个程序即使以原始内存泄漏被检测到的三倍速率运行,似乎也从来不会消耗超过0.9%的内存。两个程序泄漏了1.9%和1.3%的内存,但不会再多等。好像泄漏的内存量和泄漏的速率取决于同时运行我的程序实例的数量;这毫无道理,每个实例应该是完全独立的。
我还发现,如果我运行32个实例,只有一个实例在valgrind中运行,那么在valgrind之外运行的实例将泄漏内存,但速度比在valgrind中运行的实例要慢。valgrind实例仍然会说我没有直接泄漏,并且报告的内存消耗比Top所显示的要少得多。

我对导致这种结果的原因感到困惑,也不知道为什么valgrind无法检测到内存泄漏。我认为可能是外部库的问题,但我实际上并没有使用任何外部库,只用了基本的C++函数/对象。我还考虑过数据写入输出管道太快,导致缓冲区无限增长。但问题在于,1)这样的缓冲区应该有一个上限;2)一旦存在内存泄漏,如果我将数据输入速率降至零,内存仍然被占用,而不是缓慢地回落到合理的水平。

有人能给我一个提示,在哪里继续寻找吗?我完全不明白为什么内存会表现出这种行为。

谢谢。


3
你确定这是一个泄漏,而不仅仅是你的编程中的某些部分在收集内存吗?你尝试过使用Massif工具吗? - PlasmaHH
我自己也遇到过类似的问题(虽然不是那么古怪),我非常关心您得到的任何反馈。一个建议:您能否澄清您使用的操作系统/版本?我假设它是Linux发行版。 - Component 10
Valgrind在沙盒中运行您的程序并进行大量处理。您应该预期它具有比在valgrind之外运行的相同应用程序更高的CPU使用率和更慢的性能。我会考虑在压力测试期间,程序是否创建了额外的缓冲区来保存无法到达管道且正在增长的数据(不是泄漏,只是增长速度跟不上)。 - David Rodríguez - dribeas
等离子,如果我的程序编写正确,它不应该增长超过几KB的内存。我不会排除编写不正确的可能性,但是我认为Valgrind会显示可达内存大得多,不是吗?我从来没有尝试过massif……嗯,我之前从没听说过。我一回到办公桌就看看它是否有所帮助。 - dsollen
我目前正在运行CentOS。我使用C ++,但不是C ++ 11,如果有帮助的话。对于David来说,我不应该缓冲超过6秒的数据;数据需要及时。我已经计算了输入向量的大小,每秒向量的数量等,并且存储所需的内存大约等于当一个人结合可能泄漏和可达代码时,valgrind所显示的使用情况(可能泄漏是因为我手动杀死代码,以便在发送最后一批缓冲数据之前,该批数据尚未被正确释放)。 - dsollen
它只在存在多个实例时才出现这一事实很有趣。我肯定会关注这一点;这是真的吗?多个实例如何相互影响(套接字/网络层)?输出管道是什么?顺便问一下,您使用的是哪个套接字API? - user172783
3个回答

2

首先应该寻找软泄漏问题。当一些静态或单例对象逐渐增加某些缓冲区或容器,并将垃圾收集到其中时,此问题会发生。从技术上讲,它不是泄漏问题,但其影响与泄漏问题一样严重。


2

我建议你试试MemoryScape这个工具,它在内存泄漏检测方面做得非常好。虽然不是免费的,但考虑到花费的时间和精力,值得一试。


2
这似乎是我最近遇到的问题。
如果您的程序接受数据并在内部缓冲而没有任何限制,那么它可能读取和缓冲速度比输出数据快。在这种情况下,内存使用将继续无限增加。
您运行的程序实例越多,每个实例运行得越慢,缓冲区增长得越快。
这可能是或不是您的问题,但没有更多信息,这是我能做的最好的事情。

这是最接近准确的。我应该每隔x秒(由配置文件配置)输出数据。但由于一个错误,存储超时时间的计数器在启动时增加不正确,因此我存储了一分钟以上的数据。系统的额外负荷导致增加超时计数器的错误更容易在启动时发生。我要感谢Plasma提到的massif,它让我朝着正确的方向前进。我以为memcheck告诉我没有使用太多内存,所以我没有查看内部内存使用情况;显然我误读了memcheck。 - dsollen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接