Вопрос

У меня есть программа, в которой, частично для информационного ведения журнала, я вывожу имена некоторых классов по мере их использования (в частности, я добавляю запись в журнал, в котором говорится в соответствии с линиями 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top