【问题标题】:What happens to globally allocated memory?全局分配的内存会发生什么?
【发布时间】:2014-05-19 17:41:01
【问题描述】:

我有一个这样的程序:

int *number0 = new int;

int main()
{
    int *number1 = new int;
}

我认为,两种内存分配都会引入内存泄漏,尽管只有 valgrind 抱怨 main 函数中的 number1 。这是为什么呢?

【问题讨论】:

  • 这并不重要,因为进程终止时将释放任何内存。我猜想 valgrind 决定全局变量指向的内存不是 memleak。
  • 在你得出结论之前可以做类似 number0 的事情,但是,请记住,如果是一个类类型而不是一个 int,它的析构函数将不会被调用(也许 valgrind 在这种情况下会抱怨?)
  • @dlf:正是我的问题:我认为,由于没有 valgrind 警告,对象的析构函数(由 *number0 表示)已经以某种方式自动调用,当然不是我现在知道的情况。我也不认为让进程终止处理手动分配的内存是可以的。我不知道为什么,但它让我的脊椎发冷

标签: c++ memory-leaks global-variables valgrind


【解决方案1】:

运行这个

int *x = new int;

int main()
{   
    return 0;
}

使用 valgrind (3.8.1) 和 (-v --track-origins=yes --leak-check=full --show-reachable=yes) 的代码(即 没有 主泄漏,使用 g++ 4.8.1 编译)我得到:

==34301== 
==34301== HEAP SUMMARY:
==34301==     in use at exit: 4 bytes in 1 blocks
==34301==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==34301== 
==34301== Searching for pointers to 1 not-freed blocks
==34301== Checked 189,064 bytes
==34301== 
==34301== 4 bytes in 1 blocks are still reachable in loss record 1 of 1
==34301==    at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==34301== 
==34301== LEAK SUMMARY:
==34301==    definitely lost: 0 bytes in 0 blocks
==34301==    indirectly lost: 0 bytes in 0 blocks
==34301==      possibly lost: 0 bytes in 0 blocks
==34301==    still reachable: 4 bytes in 1 blocks
==34301==         suppressed: 0 bytes in 0 blocks

这意味着您还应该关注in use at exit 类别。

看起来 valgrind 并没有错过它,只是将它放在另一个类别中,可能是因为他们认为只有当你无法以任何方式追踪该地址并释放它时,他们才会认为某些东西丢失了,但这个变量永远不会 迷路了

但是:

int *x = new int;

int main()
{

    x = new int;    
    return 0;
}

被检测为泄漏,因为您确实丢失了已分配的内存。

编辑: 如 Mem-check manual 中所述:

“仍然可以访问”。这包括案例 1 和 2(对于 BBB 块) 以上。指向块的起始指针或起始指针链是 成立。由于块仍然指向,程序员可以,在 至少原则上,在程序退出之前释放它。 “仍然 可达”块非常常见,可以说不是问题。所以,通过 默认情况下,Memcheck 不会单独报告此类块。

所以正如他们在检测到它之前所指出的那样,他们只是认为它不那么令人兴奋

【讨论】:

    【解决方案2】:

    Valgrind 并不是检测是否存在所有可能的内存泄漏的完美工具,而是可以检测某些内存泄漏的有用工具。这意味着 valgrind 输出不能用于确定特定代码段是否包含任何泄漏。

    你的news都没有对应的deletes,从这个意义上说,它们都被泄露了。

    很可能 valgrind 认为number0 内存不会泄漏,因为它指向的内存在程序执行结束时是可以访问的。与此相反,number1 超出范围,因此它指向的内存在程序执行结束时无法访问,因此 valgrind 认为它已泄漏。

    【讨论】:

      【解决方案3】:

      我看到两个使用 valgrind 3.8.1 / g++ 4.8.1 的泄漏:

      $ g++ -o foo -g foo.cc
      $ valgrind ./foo
      ...
      ==7789== HEAP SUMMARY:
      ==7789==     in use at exit: 8 bytes in 2 blocks
      ==7789==   total heap usage: 2 allocs, 0 frees, 8 bytes allocated
      ==7789== 
      ==7789== LEAK SUMMARY:
      ==7789==    definitely lost: 4 bytes in 1 blocks
      ==7789==    indirectly lost: 0 bytes in 0 blocks
      ==7789==      possibly lost: 0 bytes in 0 blocks
      ==7789==    still reachable: 4 bytes in 1 blocks
      ==7789==         suppressed: 0 bytes in 0 blocks
      

      在我的测试中,“肯定丢失”的字节位于 main 中。

      【讨论】:

      • 恐怕你没有ones,但每个类别中只有一个(肯定有一个int(4字节)丢失的类别和仍然可以访问的类别中的一个),我认为这正是 OP 所要问的,即为什么 valgrind 将那些看似相同的泄漏放在不同的类别中。
      • 哦,现在我明白为什么复数是有意义的了 :)
      【解决方案4】:

      这个

        int *number0 = new int;
      

      不是内存泄漏,因为它在执行结束时被回收。

      此配置是 [潜在的] 内存泄漏,因为

      int main()
      {
           int *number1 = new int;
      }
      

      代码的其他部分可以调用

          main () ;
      

      并且可以重复调用。

      【讨论】:

      • C++ 程序中调用main() 是不合法的。 (参见[basic.start.main]/3:“main 函数不得在程序中使用。”)
      • 它不必是调用 C++ 例程的 C++ 程序。
      猜你喜欢
      • 1970-01-01
      • 2014-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      • 1970-01-01
      • 2013-09-07
      • 2012-11-25
      相关资源
      最近更新 更多