我有一个程序,在这个程序中,我输出了一些类的名称(具体来说,我在日志中添加了一个按照Messages::CSomeClass transmitted to 127.0.0.1的方式表示的条目),部分用于信息日志记录。我这样做的代码类似于以下代码:
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,但我想知道是否有我错过的东西。
发布于 2013-04-06 00:46:45
另一个解决方案是纠正根本问题。这不是真正的内存泄漏,只是一个错误的报告。分配给tyepinfo()和name()字符串的内存块被分配到错误的块类型。“释放”这个内存可能不是一个好主意,因为CRT将尝试再次释放它。好消息是,VS2012 (_MSC_VER 1700+)终于解决了这个问题。
由于这只适用于_DEBUG构建,以下可能是一个更安全的解决方案。在退出模块入口点(main、WinMain等)之前,应该像前面提到的那样调用函数_FixTypeInfoBlockUse()。
#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)发布于 2012-06-23 21:01:56
我刚刚偶然发现了这个问题,试图清理VLD日志。是的,这是一个已知臭虫,它只在VC11中固定。它存在于MSVC的早期版本,包括2010年。只有在使用MFC时才会出现此错误。如果使用MFC作为DLL而不是静态库,则内存泄漏仍然存在,但不会被检测到。
有一个type_info名称的全局缓存,它没有被清除(摘自<typeinfo>):
struct __type_info_node {
void *_MemPtr;
__type_info_node* _Next;
};
extern __type_info_node __type_info_root_node;这样做是为了清除这个缓存。这一职能适用于我:
#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注册它
#include <cstdlib>
int WinMain(...)
{
atexit(&clear_type_info_cache);
...
}或者在离开WinMain之前立即打电话
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;
...
}发布于 2011-11-29 11:24:21
正如Chris在评论中指出的,这似乎是一个已知臭虫,至少对于我正在使用的编译器版本来说--如果我能够升级到VC11,升级到VC11将会纠正这个问题。
尝试删除typeinfo::name()的输出部分有效:
std::string getMessageName(void) const
{
std::string typeStr(typeid(*this).name());
delete (typeid(*this).name());
return typeStr;
}然而,仍然存在一些内存泄漏--我只是注意到,以前我似乎每次调用都会有两个泄漏(可能是因为类在名称空间中?)。使用上述版本的代码,这可以归结为每次调用一次泄漏。
另一个可行的解决方案是链接到MFC库的动态版本中(是的,我正在使用MFC,不要评判我),而不是静态版本。
https://stackoverflow.com/questions/8308671
复制相似问题