【问题标题】:c++ memory leak when using std::string in shared memory arrayc++ 在共享内存数组中使用 std::string 时内存泄漏
【发布时间】:2011-08-27 05:46:57
【问题描述】:

我有这门课

class LayoutEntry
{
  unsigned int id_;
  string name_;  
  bool isInput_;
};

复制构造函数如下所示:

LayoutEntry(const LayoutEntry &other)
        : id_(other.id_),
        name_(other.name_), 
        isInput_(other.isInput_)
    {
    }

这个类的对象被放在另一个类的映射中

class DataLayoutDescription 
{
    unsigned int sz_;
    set<LayoutEntry, SortByOffset> impl;

    // HERE!!!
    map<unsigned int, LayoutEntry> mapById;

这个类的拷贝构造函数如下所示:

DataLayoutDescription::DataLayoutDescription(const DataLayoutDescription &other)
    :sz_(other.sz_), impl(other.impl), mapById(other.mapById)
{   
}

现在的问题:

  • 当像打印一样运行时,每个 LayoutEntry 都会出现内存泄漏
  • 如果我在 DataLayoutDescription 的复制构造函数中删除 mapById(other.mapById) 则没有 memleak
  • 如果我删除name_(other.name_),,内存泄漏也消失了

为什么?

编辑

对于测试,我在最后使用 BOOST::UnitTest 我得到一个内存泄漏转储

C:\wc\05_EAPGit\Debug>EapLibTest.exe --run-test=SharedVectorTest
Running 7 test cases...

*** No errors detected
Detected memory leaks!
Dumping objects ->
{1378} normal block at 0x005815C0, 16 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
{1377} normal block at 0x00581580, 16 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
{1376} normal block at 0x00581540, 16 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

可能的原因? 我使用此方法将 DataLayoutDescription 保存在共享内存区域中

void DataLayoutDescription::Save(LayoutEntry *les, unsigned int maxEntries) const
{
    int n = std::max(impl.size(), maxEntries);
    int i = 0;
    for (DataLayoutDescription::iterator it = begin(); it != end(); ++it)
    {
        les[i] = *it;  // Source of memory leak here???
        ++i;
    }
}

我取消引用迭代器 ant 将其副本存储在位于共享内存区域的数组中。有什么不对?共享内存在退出时被删除。

进一步追踪 LayoutEntry 类放置在共享内存区域内的数组中,并包含一个字符串。内存泄漏的原因是字符串被调整大小。因此它在堆上分配了更多的内存。现在我猜这个内存不会被释放,因为原始内存位于共享内存中。这可能是原因吗?接下来我将尝试删除字符串并将其替换为固定长度的 char 数组。

...几分钟后

就是这样。用固定的 char 数组替换字符串后,内存泄漏消失了。希望这对某人有所帮助。

【问题讨论】:

  • 这看起来很完美。是什么让你觉得这里有内存泄漏?
  • 您发布的代码中没有明显的内存泄漏。为什么你认为你有一个?
  • @schoetbi:如果您运行该程序两次,该转储中的分配编号是否相同?
  • @sharptooth:是的,如果我不更改代码,分配数字将保持不变
  • @nos: DataLayoutDescription 在堆栈上

标签: c++ memory-leaks


【解决方案1】:

看起来像the memory leak that was introduced in Visual Studio 2010 C++ standard library, fixed with SP1。如果是您的编译器(没有 SP1),那肯定是问题所在。

另请参阅这些答案:STL container leak

【讨论】:

  • 我接受这个不是因为它对我来说是最简单的答案,而是症状看起来像它。我还没有完成你建议的所有事情,但因为我也泄漏了 16 个字节,所以看起来像这样。仍然困扰我的一件事是我安装了 SP1。
  • 如果您安装了 VS2010 SP1,请按照我在链接中接受的答案(甚至没有说明它是来自我...)。
【解决方案2】:

假设当你说你有内存泄漏时,你的意思是像 Purify 或 valgrind 这样的检查器告诉你,最有可能的情况是你以某种方式泄漏了 LayoutEntry 对象,而不是直接泄漏 string 对象。我曾经被这个咬过并且很困惑,因为我自己的对象被泄漏了,但是泄漏被(由 valgrind)标记为std::string,这使得它更难找到。

或者,它可能只是检测到增长。您是否尝试在退出之前在地图上输入clear

【讨论】:

    【解决方案3】:

    泄漏的原因是存储字符串的 LayoutEntry 类。基础对象(修改前)被放置在共享内存区域内的数组中。更改字符串后,执行了调整大小操作,这块内存丢失了。用字符数组(固定长度)替换字符串后,内存泄漏消失了。我现在很高兴,但问自己字符串类是否做错了,或者有没有办法将自定义分配器放入 std::string?我不需要这个,因为我将使用 char 数组,但我只是好奇这样的事情是否可行并且天气我对这个假设是否正确?

    这是修改后的类

    class LayoutEntry
    {
      unsigned int id_;
      char name_[128];  
      bool isInput_;
    };
    

    感谢大家的帮助!调试内存泄漏的技巧对我帮助很大。

    【讨论】:

    • C++ 字符串分配更多内存来保存实际字符串。您复制到共享内存中的只是一个指针和长度。实际的字符串从未在共享内存中,因此当您删除共享内存时,您会丢失本应调用 delete[] 的指针。
    【解决方案4】:

    如果您在泄漏中有一致的分配编号,您可以使用_CrtSetBreakAlloc 将调试内存分配器设置为在该特定分配处中断。

    http://msdn.microsoft.com/en-us/library/4wth1ha5.aspx

    例如,在代码中添加_CrtSetBreakAlloc(1378) 会在分配块号 1378 时导致调试中断。然后您可以使用调试器将代码跟踪回调用方。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-26
      • 1970-01-01
      • 2011-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-18
      相关资源
      最近更新 更多