Утечки памяти после использования typeinfo :: name ()
-
25-10-2019 - |
Вопрос
У меня есть программа, в которой, частично для информационного ведения журнала, я вывожу имена некоторых классов по мере их использования (в частности, я добавляю запись в журнал, в котором говорится в соответствии с линиями 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()
Появляется как утечка памяти. Если я выведу информацию для 2 классов, я получаю 2 утечки памяти и так далее. Это намекает на то, что кэшированные данные никогда не освобождаются.
Хотя это не является серьезной проблемой, она выглядит грязно, и после долгой сессии отладки он может легко скрыть подлинные утечки памяти.
Я оглянулся и нашел некоторую полезную информацию (один, поэтому ответ дает некоторую интересную информацию о Как может быть реализован TypeInfo), но мне интересно, должна ли эта память обычно освобождаться системой, или есть ли что -то, что я могу сделать, чтобы «не заметить» утечки при отладке.
У меня есть резервный план, который должен кодировать getMessageName
метод сам и не полагаюсь на typeinfo::name
, но я все равно хотел бы знать, есть ли что -то, что я пропустил.
Решение
Другое решение - исправить основную проблему. Это не утечка памяти, просто ложный отчет. Блоки памяти, выделенные по строке tyepinfo () и name (), назначаются неправильный тип блока. Вероятно, не очень хорошая идея «освободить» эту память, так как CRT будет предпринята попытка освободить ее снова. Хорошая новость заключается в том, что это было наконец исправлено в VS2012 (_MSC_VER 1700+).
Поскольку это относится только к сборке _debug, следующее может быть более безопасным решением. Функция _fixtypeinfoblockuse () должна быть названа, как указано выше, непосредственно перед тем, как выходить из точки входа модуля (Main, Winmain и т. Д.).
#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)
Другие советы
Я только что наткнулся на эту проблему, пытаясь очистить журнал Вд. Анкет Да, это известная ошибка, который зафиксирован только в 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;
...
}
Как указал Крис Партон в комментариях, это кажется известная ошибка, по крайней мере, с версией компилятора, которую я использую - обновление до VC11 исправят проблему, если бы я смог обновить.
Попытка удалить вывод typeinfo::name()
частично работает:
std::string getMessageName(void) const
{
std::string typeStr(typeid(*this).name());
delete (typeid(*this).name());
return typeStr;
}
Однако все еще есть некоторые утечки памяти - я только что заметил, что ранее я, похоже, получал две утечки за вызов (возможно, из -за классов в пространстве имен?). Используя приведенную выше версию кода, это сократилось до одной утечки за вызов.
Другое решение, которое, по -видимому, работает, состоит в том, чтобы связать динамическую версию библиотек MFC (да, я использую MFC, не судите меня), а не статическую версию.
VS Магазины Тип Информация в отдельном списке. Заголовок этого списка доступен в непрозрачной структуре, доступной по имени __type_info_root_node. Анкет На самом деле это структура slist_header.
Win32 API обладает набором параллелизма, безопасной для работы с такими структурами. Чтобы исправить отчет о утечках памяти в вашем случае, вам нужно удалить все узлы этого списка.
#include <Windows.h>
#include <typeinfo>
#include <vld.h>
void ClearTypeinfoCache()
{
#ifdef _DEBUG
while (auto entry = InterlockedPopEntrySList(reinterpret_cast<PSLIST_HEADER>(&__type_info_root_node)))
{
free(entry);
}
#endif
}
int main()
{
atexit(ClearTypeinfoCache);
return 0;
}
Обновлено: VLD 2.5.1 не сообщает о утечках памяти на type_info :: name () в VS2015 Обновление 3.