围绕新建/删除编写内存分析包装器的合适方法是什么?

What is an appropriate way to write a memory profiling wrapper around new/delete?

提问人:Sankalp Sangle 提问时间:2/22/2021 更新时间:2/22/2021 访问量:136

问:

我希望了解如何为我所做的调用编写一个好的包装器来进行内存分析。 在 C 语言中,我的包装器看起来像这样。 对于 calloc,.这将在内部使用一些结构来跟踪分配了多少字节的内存以及对 calloc 的调用次数,创建 void 指针并返回它。 免费,它会像我传递的大小一样,其中 T 是 .void* wrapperCalloc(size_t nitems, size_t size)void wrapperFree(void* ptr, size_t size)sizeof(*T)ptr

我现在在 C++ 中的问题是我不知道我的新包装器的返回类型是什么,因为我们在 C++ 中使用它在内部确定类型并相应地返回类型化指针。new

C++ malloc wrapper new-operator 免费

评论

0赞 Aykhan Hagverdili 2/22/2021
看看这是否有助于 codereview.stackexchange.com/q/238533/183642
0赞 Sankalp Sangle 2/22/2021
非常感谢,这很有帮助。我不完全了解模板,但我会花时间理解它,因为它似乎符合我的目的。
0赞 Jarod42 2/22/2021
对于大多数主题,在 C++ 中有几种方法可以做到这一点,这也取决于您要检查的级别(为某些容器类定义特定的分配器,在类范围或全局范围重载 new/delete)。
0赞 Aykhan Hagverdili 2/22/2021
我链接中的示例跟踪分配/解除分配,以检测内存泄漏和双重释放。您可以将其用作自定义包装器的示例。

答:

0赞 Aykhan Hagverdili 2/22/2021 #1

C++ 有“分配器”的概念。这是一个特定的类,旨在抽象内存管理的细节。所有 STL 容器都将此作为模板参数。他们传递一个分配器,并将其用作内存源。如果这适合您的设计,请使用它并创建自定义分配器。


控制内存管理的较低级别方法是重载运算符 new/delete。这些运算符可以针对单个类或整个系统重载:

#include <cstdlib>
#include <exception>

void*
operator new(std::size_t sz)
{
  if (!sz) sz = 1; // can't allocate 0 bytes
  if (void* p = std::malloc(sz)) return p;
  throw std::bad_alloc{};
}

void*
operator new[](std::size_t sz)
{
  if (!sz) sz = 1; // can't allocate 0 bytes
  if (void* p = std::malloc(sz)) return p;
  throw std::bad_alloc{};
}

void
operator delete(void* const ptr) noexcept
{
  std::free(ptr);
}

void
operator delete[](void* const ptr) noexcept
{
  std::free(ptr);
}

当您执行类似 .需要注意的一点是,您在这些函数中使用的数据结构本身不应调用 new/delete,否则会导致无限递归。因此,如果您在实现这些函数时需要 STL 容器,请为 STL 容器制作某种 malloc-allocator。new T[100]


您还可以查看 cppcon 演讲,了解有关分配器的更多信息。

评论

0赞 Sankalp Sangle 2/22/2021
谢谢你的评论。我没有使用运算符重载,但我会研究它。但是当我说例如new MyClass();您是否建议构造函数调用是一个单独的步骤,由编译器自行插入?
0赞 Aykhan Hagverdili 2/22/2021
@SankalpSangle 是的,调用构造函数/析构函数由编译器单独处理。这些运算符只关心内存分配/解除分配。您只需在全局范围内定义这些内容,并且要格外小心,以免引起无限递归。
0赞 Sankalp Sangle 2/22/2021
谢谢。最后,是否可以在特定作用域中重载新运算符,以便我可以仅针对要跟踪的某些类/作用域实现内存分析?
0赞 Aykhan Hagverdili 2/22/2021
@SankalpSangle是的,当然。您可以重载类级运算符 new/delete,它只会处理该类。 STL 容器还具有“分配器”的概念,它也很有用。查找它们。