在MSVC ++中覆盖内存分配器

时间:2012-10-10 09:15:04

标签: c++ visual-c++ visual-c++-2008 c++03

虽然Microsoft标准运行时提供分配函数的调试版本,但实际上并不起作用,因为您不应该在C ++代码中使用裸新,因此检测指向标准库,或者因为标准库不能无论如何都是仪表化的。

现在我有了可以生成(并记录)分配回溯的代码,我也使用了DUMA。但是,当我们使用流时,替换分配函数的尝试就会中断,因为streambuf调用了某些调试变体,并且在new和delete之间不一致。

在Microsoft标准运行时中,是否有人通过覆盖函数而不是丑陋的预处理器技巧来替换allocator?我怀疑它涉及避免调试分配器,但我想保留_DEBUG定义的原因显而易见(更多的调试代码取决于它)。

注意:我们目前仍处于使用Visual C ++ 9.0(Visual Studio 2008)。

编辑:避免调试分配器不太可能是一个选项,因为C ++标准库需要在编译到库的函数和实例化与用户代码中生成的实例化之间具有一致的new和delete定义,因为分配可能是一个完成,另一个释放。顺便说一下,在强制包含标题中定义静态内联变体不太可能削减它。

Edit2:动态链接是不可能的,因为Windows绑定来自特定DLL的符号,因此无法在链接时覆盖它们。但是我们不需要动态链接而不使用它,因为主要目标是WinCE,静态链接是默认链接。

1 个答案:

答案 0 :(得分:1)

这是我们如何做到的(使用jemalloc,但任何其他分配器都是可能的):

  1. 将自定义内存分配器单独编译为C静态库。
  2. 将C ++应用程序与自定义分配器库链接。
  3. 覆盖C ++应用程序中的运算符newdelete以调用自定义分配器。
  4. 注意:

    • 自定义分配器必须用C语言编写,而不是用C ++编写。
    • 除非它位于单独的库中,否则无法确保分配器的充分早期初始化。
    • 覆盖mallocfree也是可能的,但在MSVC中要难得多,因为它们并非“弱”链接,并且因为MSVC中有很多自定义变体(例如使用/FORCE:MULTIPLE链接器标志)。

    示例代码:

    void* operator new(size_t size)
    {
      void* ptr = my_malloc(size);
      if (ptr)
        return ptr;
      else
        throw std::bad_alloc();
    }
    
    void* operator new[](size_t size)
    {
      void* ptr = my_malloc(size);
      if (ptr)
        return ptr;
      else
        throw std::bad_alloc();
    }
    
    void* operator new(size_t size, const std::nothrow_t&) throw()
    {
      return my_malloc(size);
    }
    
    void* operator new[](size_t size, const std::nothrow_t&) throw()
    {
      return my_malloc(size);
    }
    
    void operator delete(void* pointer) throw()
    {
      my_free(pointer);
    }
    
    void operator delete[](void* pointer) throw()
    {
      my_free(pointer);
    }
    
    void operator delete(void* pointer, const std::nothrow_t&) throw()
    {
      my_free(pointer);
    }
    
    void operator delete[](void* pointer, const std::nothrow_t&) throw()
    {
      my_free(pointer);
    }