首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用typeinfo::name()后内存泄漏

使用typeinfo::name()后内存泄漏
EN

Stack Overflow用户
提问于 2011-11-29 09:46:59
回答 4查看 2.1K关注 0票数 8

我有一个程序,在这个程序中,我输出了一些类的名称(具体来说,我在日志中添加了一个按照Messages::CSomeClass transmitted to 127.0.0.1的方式表示的条目),部分用于信息日志记录。我这样做的代码类似于以下代码:

代码语言:javascript
复制
std::string getMessageName(void) const {
    return std::string(typeid(*this).name());
}

是的,在任何人指出之前,我意识到typeinfo::name的输出是特定于实现的。

根据MSDN

type_info::name成员函数将一个const char*返回到一个以空结尾的字符串,该字符串表示该类型的可读的名称。指向的内存被缓存,不应直接释放。

但是,当我在调试器中退出程序时,typeinfo::name()的任何“新”用法都会显示为内存泄漏。如果我输出两个类的信息,就会得到两个内存泄漏,依此类推。这表明缓存的数据从未被释放。

虽然这不是一个主要的问题,但它看起来很混乱,经过长时间的调试,它可以很容易地隐藏真正的内存泄漏。

我环顾四周,发现了一些有用的信息(其中一个答案给出了一些关于如何实现typeinfo的有趣信息),但我想知道这个内存是否应该通常由系统释放,或者在调试时我是否可以做一些“不注意”泄漏的事情。

我确实有一个备份计划,就是自己编写getMessageName方法,而不是依赖于typeinfo::name,但我想知道是否有我错过的东西。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-04-06 00:46:45

另一个解决方案是纠正根本问题。这不是真正的内存泄漏,只是一个错误的报告。分配给tyepinfo()和name()字符串的内存块被分配到错误的块类型。“释放”这个内存可能不是一个好主意,因为CRT将尝试再次释放它。好消息是,VS2012 (_MSC_VER 1700+)终于解决了这个问题。

由于这只适用于_DEBUG构建,以下可能是一个更安全的解决方案。在退出模块入口点(main、WinMain等)之前,应该像前面提到的那样调用函数_FixTypeInfoBlockUse()。

代码语言:javascript
复制
#if defined(_DEBUG) && (_MSC_VER >= 1000 && _MSC_VER <= 1699)
//
// Debug memory block header:
//    o  Borrowed from the Microsoft CRT to fix the false "memory leak" report
//       when using typeinfo 'name' accessor in a _DEBUG build of the library.  
//
struct _CrtMemBlockHeader
   {
   struct _CrtMemBlockHeader * pBlockHeaderNext;
   struct _CrtMemBlockHeader * pBlockHeaderPrev;
   char *                      szFileName;
   int                         nLine;
   #ifdef _WIN64
   int                         nBlockUse;
   size_t                      nDataSize;
   #else
   size_t                      nDataSize;
   int                         nBlockUse;
   #endif
   long                        lRequest;
   unsigned char               gap[4];
   };

static void __cdecl _FixTypeInfoBlockUse(void)
   {
   __type_info_node* pNode = __type_info_root_node._Next;

   while(pNode != NULL)
      {
      __type_info_node* pNext = pNode->_Next;

      (((_CrtMemBlockHeader*)pNode) - 1)->nBlockUse = _CRT_BLOCK;

      if (pNode->_MemPtr != NULL)
         (((_CrtMemBlockHeader*)pNode->_MemPtr) - 1)->nBlockUse = _CRT_BLOCK;

      pNode = pNext;
      }
   }

#endif//defined(_DEBUG) && (_MSC_VER >= 1000 && _MSC_VER <= 1699)
票数 4
EN

Stack Overflow用户

发布于 2012-06-23 21:01:56

我刚刚偶然发现了这个问题,试图清理VLD日志。是的,这是一个已知臭虫,它只在VC11中固定。它存在于MSVC的早期版本,包括2010年。只有在使用MFC时才会出现此错误。如果使用MFC作为DLL而不是静态库,则内存泄漏仍然存在,但不会被检测到。

有一个type_info名称的全局缓存,它没有被清除(摘自<typeinfo>):

代码语言:javascript
复制
struct __type_info_node {
    void *_MemPtr;
    __type_info_node* _Next;
};

extern __type_info_node __type_info_root_node;

这样做是为了清除这个缓存。这一职能适用于我:

代码语言:javascript
复制
#include <typeinfo>

void clear_type_info_cache()
{
   __type_info_node* & node = __type_info_root_node._Next;
   while(node)
   {
      if (node->_MemPtr)
      {
         delete node->_MemPtr;
      }
      __type_info_node* tempNode = node;
      node = node->_Next;
      delete tempNode;
   }
}

出口前打电话给clear_type_info_cache()。您可以在atexit注册它

代码语言:javascript
复制
#include <cstdlib>

int WinMain(...)
{
   atexit(&clear_type_info_cache);
   ...
}

或者在离开WinMain之前立即打电话

代码语言:javascript
复制
struct dummy_scope_exit
{
   typedef void (*Fun)();
   dummy_scope_exit(Fun f) : m_f(f) {}
   ~dummy_scope_exit() { m_f(); }
   Fun m_f;
};

int WinMain(...)
{
   dummy_scope_exit cleaner = &clear_type_info_cache;
   ...
}
票数 4
EN

Stack Overflow用户

发布于 2011-11-29 11:24:21

正如Chris在评论中指出的,这似乎是一个已知臭虫,至少对于我正在使用的编译器版本来说--如果我能够升级到VC11,升级到VC11将会纠正这个问题。

尝试删除typeinfo::name()的输出部分有效:

代码语言:javascript
复制
std::string getMessageName(void) const
{
    std::string typeStr(typeid(*this).name());
    delete (typeid(*this).name());
    return typeStr;
}

然而,仍然存在一些内存泄漏--我只是注意到,以前我似乎每次调用都会有两个泄漏(可能是因为类在名称空间中?)。使用上述版本的代码,这可以归结为每次调用一次泄漏。

另一个可行的解决方案是链接到MFC库的动态版本中(是的,我正在使用MFC,不要评判我),而不是静态版本。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8308671

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档