【问题标题】:When can a memory leak occur?什么时候会发生内存泄漏?
【发布时间】:2011-05-13 21:00:41
【问题描述】:

我不知道该怎么想……

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

现在,当您遇到 bad_alloc 异常时,您认为这是内存泄漏。但是所有我们的手动分配都包装在一个智能指针中。此外,我无法理解当整个进程仅使用 ~50Mb 时 stringstream 对象是如何缺乏内存的(内存使用量每天都保持大致恒定(并且肯定不会增加)。

我不能给你代码,因为这个项目真的很大,而抛出异常的部分真的什么都不做,只是创建一个字符串流和

所以,我的问题是......当进程仅使用 2GB 中的 50Mb 内存时,如何发生内存泄漏/bad_alloc?对于可能出现的问题,您还有哪些疯狂的猜测?

在此先感谢,我知道这个问题含糊不清等,我有点绝望,我尽力解释了这个问题。

【问题讨论】:

  • @skwllsp:我简直不敢相信,当只使用 50 MB 时,内存碎片会导致分配 1~2kb 内存失败......可以吗?
  • 如果这是碎片,我无法理解为什么在足够的运行时间后它不会在本地发生。似乎重现特定于另一台机器的某些特性。
  • 当你说它使用只有 50Mb 时,你的意思是它在内存中的大小永远不会超过 50Mb,或者它的分配加起来不会超过 50Mb?一个小程序可以很容易地分配/释放比它在任何给定时刻使用的更多的内存,并且垃圾收集可能因机器而异。

标签: c++ memory-leaks windows-xp


【解决方案1】:

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

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

现在如果 numberOfElements 未初始化,它可能包含一些不合理的大数字,因此您有效地尝试分配内存管理器拒绝分配的 3GB 块。

因此,可能不是您的程序内存不足,而是它尝试分配的内存超出了在最佳条件下可能允许的内存。

【讨论】:

    【解决方案2】:

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

    您还可以使用Valgrind 或其Windows replacements 之一来查找泄漏/溢出。

    【讨论】:

      【解决方案3】:

      只是预感,

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

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

      当 SIZE 很大时。

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

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

      我发现这非常令人困惑,原因原来是 Martin York 在解决方案中讨论的堆栈帧: Is there a max array length limit in C++?

      一切顺利,

      汤姆

      【讨论】:

        【解决方案4】:

        使用来自 sysinternals 的 Process Explorer 检查机器上其他进程的配置文件 - 如果内存不足,即使不是您造成内存压力,您也会得到 bad_alloc

        使用umdh 检查您自己的内存使用情况,以获取快照并比较一段时间内的使用情况。您必须在周期的早期执行此操作以避免损坏工具,但如果您的进程的行为没有随着时间的推移而退化(即没有突然的病态行为),您应该在T 时获得有关其内存使用情况的准确信息与时间T+t.

        【讨论】:

        • Process Explorer 显示Virtual Size 以及其他详细的每个进程统计信息 - 如果一个或多个进程是贪婪的,它会告诉你。
        【解决方案5】:

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

        如果是这种情况,并且如果您在第一天使用该功能(没有意外),那么您可以将字符串流设为静态变量并重用它。据我所知,stringstream 在其生命周期内不会释放它的缓冲区空间,所以如果它在第一天建立一个大缓冲区,它将从那时起继续拥有它(为了增加安全性,你可以在它运行一个 5Kb 虚拟字符串时它是首先构造的)。

        【讨论】:

          【解决方案6】:

          我不明白为什么流会抛出。你没有失败进程的转储吗?或者也许附加一个调试器来查看分配器试图分配什么?

          但如果您确实重载了operator <<,那么您的代码可能确实存在错误。

          就我的 2(欧元)cts...

          1。碎片化?

          内存可能是碎片化的。

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

          注意:这个答案是在我阅读之前写的,排除了这种可能性。

          2。有符号还是无符号?

          另一种可能性是对要分配的大小使用带符号的值:

          char * p = new char[i] ;
          

          如果i 的值为负数(例如-1),则转换为无符号整数size_t 将使其超出内存分配器可用的范围。

          由于有符号整数的使用在用户代码中非常普遍,如果仅用作无效值的负值(例如 -1 表示搜索失败),这是有可能的。

          【讨论】:

            【解决方案7】:
             ~className(){
            
             //delete stuff in here
            
            }
            

            【讨论】:

              【解决方案8】:

              例如,当您在 c++ 中使用 new 运算符而忘记使用 delete 运算符时,可能会发生内存泄漏。

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

              【讨论】:

                猜你喜欢
                • 2018-06-08
                • 2011-06-28
                • 1970-01-01
                • 2021-08-15
                • 2013-04-01
                • 2016-01-01
                • 1970-01-01
                • 2011-10-25
                • 2014-06-10
                相关资源
                最近更新 更多