问题 何时可能发生内存泄漏?


我不知道在这里想些什么......

我们有一个作为服务运行的组件。它在我的本地机器上运行得非常好,但在其他一些机器上(两台机器上的RAM都等于2GB),它会在第二天和连续几天开始生成bad_alloc异常。问题是该过程的内存使用量保持不变,大约为50Mb级别。另一个奇怪的事情是,通过跟踪消息,我们已经定义了从stringstream对象抛出的异常,该对象只会向流中插入不超过1-2 Kb的数据。如果这很重要,我们正在使用STL-Port。

现在,当您收到bad_alloc异常时,您认为这是内存泄漏。但 所有 我们的手动分配包含在智能指针中。此外,当整个过程仅使用~50Mb(内存使用量每天保持不变(并且肯定不会上升))时,我无法理解stringstream对象如何缺少内存。

我无法为您提供代码,因为项目非常大,抛出异常的部分除了创建字符串流和<<某些数据然后记录之外别无其他功能。

所以,我的问题是......当进程只使用2GB的50Mb内存时,如何发生内存泄漏/ bad_alloc?你有什么其他的猜测可能是错的?

提前谢谢,我知道这个问题很模糊,我只是有点绝望,我尽力解释这个问题。


12230
2017-11-22 14:17


起源

@skwllsp:我只是不相信内存碎片可能导致在使用50 MB时分配1~2kb内存失败...可以吗? - Armen Tsirunyan
如果这是碎片,我无法理解为什么在足够的运行时之后它不会在本地发生。似乎repro特定于其他机器的某些特性。 - Steve Townsend
当你说出来的时候 使用 只有50Mb,你的意思是它在内存中的大小永远不会超过50Mb,或者它的分配不超过50Mb?一个小程序可以轻松分配/释放比在任何给定时刻使用更多的内存,垃圾收集可能因机器而异。 - Beta


答案:


bad_alloc 并不一定意味着没有足够的记忆。分配函数也可能因为堆已损坏而失败。您可能有一些缓冲区溢出或代码写入已删除的内存等。

你也可以使用 Valgrind的 或其中一个 Windows替换 找到泄漏/溢出。


4
2017-11-22 14:33





在您的描述中,一个可能的原因是您尝试分配一些不合理的大块,因为代码中存在错误。像这样的东西;

 size_t numberOfElements;//uninitialized
 if( .... ) {
    numberOfElements = obtain();
 }
 elements = new Element[numberOfElements];

现在如果 numberOfElements 如果没有初始化它可能包含一些不合理的大数字,所以你有效地尝试分配一个3GB的块,内存管理器拒绝这样做。

所以它可能不是你的程序内存不足,而是它试图分配比在最佳条件下可能允许的内存更多的内存。


5
2017-11-22 14:32



+1这是我的第一个念头。 - Mark B


只是一种预感,

但是我在过去分配数组时遇到了麻烦

int array1[SIZE];  // SIZE limited by COMPILER to the size of the stack frame

当SIZE是一个很大的数字。

解决方案是使用新运算符进行分配

int* array2 = new int[SIZE];  // SIZE limited only by OS/Hardware

我发现这非常混乱,原因是Martin York在解决方案中讨论的堆栈框架: C ++中是否存在最大数组长度限制?

祝一切顺利,

汤姆


1
2017-11-22 14:28





使用查看机器上其他进程的配置文件 Process Explorer 从sysinternals - 你会得到 bad_alloc 如果记忆很短,即使不是你造成记忆压力。

使用检查自己的内存使用情况 UMDH 获取快照并比较一段时间内的使用情况。你必须在周期的早期做到这一点,以避免炸毁工具,但如果你的过程的行为没有随着时间的推移而降低(即没有突然的病态行为),你应该及时获得有关其内存使用情况的准确信息 T 与时间 T+t


1
2017-11-22 14:28



虚拟内存怎么样? - Armen Tsirunyan
Process Explorer显示 Virtual Size 其他详细的每个流程统计数据 - 如果一个或多个流程贪婪,它会告诉你。 - Steve Townsend


另一个远景:你没有说出错误发生在三个操作中的哪一个(构造, << 或日志),但问题可能是内存碎片,而不是内存消耗。也许stringstream找不到足够长的连续内存块来容纳几个Kb。

如果是这种情况,并且如果您在第一天运行该功能(没有发生事故),那么您可以将stringstream作为静态变量并重复使用它。据我所知,stringstream在其生命周期内没有释放缓冲区空间,因此如果它在第一天建立一个大缓冲区,它将从那时开始继续使用它(为了增加安全性,你可以通过它运行一个5Kb的虚拟字符串。它是第一次构建)。


0
2017-11-22 14:49





我不明白为什么一个流会抛出。你没有转储失败的进程吗?或者可能附加调试器以查看分配器尝试分配的内容?

但如果你确实超载了 operator <<,那么也许你的代码确实有一个bug。

只是我的2(欧元)cts ......

1.碎片?

内存可能是碎片化的。

有一次,您尝试分配SIZE字节,但分配器在内存中找不到连续的SIZE字节块,然后抛出bad_alloc。

注意:这个答案是在我读到这个可能性被排除之前写的。

签名与未签名?

另一种可能性是使用已签名的值来分配大小:

char * p = new char[i] ;

如果值 i 是负数(例如-1),投入无符号积分 size_t 将使它超越内存分配器可用的内容。

由于有符号积分的使用在用户代码中非常常见,如果仅用作无效值的负值(例如,对于失败的搜索,则为-1),这是可能的。


0
2017-11-22 14:44





 ~className(){

 //delete stuff in here

}

0
2017-07-23 19:28





举例来说,使用时可能会发生内存泄漏 new 在c ++中运算符而忘记使用了 delete 运营商。

或者,换句话说,当您分配一块内存并忘记释放它时。


-1
2018-06-23 23:35