【问题标题】:Get size of memory available on the heap获取堆上可用的内存大小
【发布时间】:2017-07-07 20:54:15
【问题描述】:

这是 Linux 的平台相关问题。如果这很重要,我特意询问的是 C++11 之前的版本。

我想通过newdelete 间接测试一个类的析构函数,看看程序堆上的所有内存是否都被释放,这可以检查内存泄漏。

object* x;        //pointer allocated on the stack
...               //measure available heap space
x = new object(); //allocated on the heap
delete x;         //deallocate that heap space
...               //measure again, see if it's the same

我知道 Valgrind 有 Massif(……有 Massif 的 C++ 库吗……?),我什至可以对我的整个程序运行内存泄漏检查,但代码会发生变化。单元测试很重要,我无法对所有代码进行完全单元测试,这让我烦死

我可以编写什么代码来测量可用堆空间?

【问题讨论】:

  • 我会说这是错误的方法——“available”堆空间随着时间的推移并不是一个常数。映射到您的进程的内存将发生变化,因为分配器会调用操作系统特定的 API,例如 sbrk()mmap()。那么什么是“可用”?只有当前映射到您的流程的内容?或者你的进程可能被映射的所有内存?后者更加复杂(linux overcommits,顺便说一句)。另一种方法可以工作(但当然取决于实现):测量已用堆空间的数量。
  • 总而言之,您可能会“更快乐”地做其他人所做的事情:对您的实际业务逻辑使用单元测试,并定期使用valgrind 之类的工具查找内存处理错误(调用它是一个集成测试) ;)
  • 典型的解决方案是使用ASAN (address sanitizer) 或您自己说的在valgrind 下运行单元测试。我不确定你为什么要从程序中测量它。只需运行一个创建和删除对象的单元测试,然后告诉您的测试驱动程序在 valgrind 下运行该测试。
  • 如果您希望能够在不运行在单独的调试环境中的情况下跟踪堆使用情况(即,无论出于何种原因,您不喜欢在 valgrind 下运行),您可以重载 C++ 的 new 和 delete 运算符跟踪和报告您的程序在任何给定时间分配了多少字节的内存。一个例子在这里:almostinfinite.com/memtrack.html

标签: c++ linux unit-testing memory-leaks heap-memory


【解决方案1】:

在 Linux 中栈和堆之间的区别有些模糊。堆栈只是内存,它的顶部被传递给创建新任务的clone() 调用。对于新进程和新线程都是如此。分配器运算符是系统调用brk/sbrk 的包装器。最好的办法是覆盖全局 operator new/operator new[]operator delete/operator delete[] 以对调用进行某种计数,以便在运行时对其进行检查。

快速阅读new expression 可以让您很好地了解创建/销毁对象时发生的事情的顺序(如果您已经知道这一点,请原谅我),operator new 将告诉您分配器的顺序抬头看。我可能对此有误,但为了让所有分配器都经过从操作系统请求内存的同一点,即使是特定于类的operator new 最终也必须调用全局operator new

好吧,特定于类的可以使用分配器到mmap 内存到文件或shmget 将对象映射到共享内存中的某个存储,但在这两种情况下,它都不属于传统上称为“堆”的东西。当您在 linux 中运行“top”时,堆栈和堆都驻留在您所看到的“VIRT”内存中。

简而言之,malloc 分配并传递给clone 调用(例如,创建一个新线程)作为新线程堆栈的内存与用作堆。

【讨论】:

  • 感谢您的链接,我对这一切还是陌生的,我一定会读一读。我承认我可能只是在这里寻找错误的解决方案,我可能应该按照@Ilya Popov 对 Valgrind 的建议去做。再次感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-05
  • 1970-01-01
  • 2011-03-18
  • 2011-05-03
  • 1970-01-01
  • 2011-09-24
相关资源
最近更新 更多