c++ visual-c++ memory-leaks typeid typeinfo

c++ - Pérdidas de memoria después de usar typeinfo:: name()



visual-c++ memory-leaks (4)

Como lo señaló Chris Parton en los comentarios, este parece ser un error conocido , al menos con la versión del compilador que estoy usando: la actualización a VC11 corregirá el problema, si pudiera actualizarlo.

Intentar eliminar el resultado de typeinfo::name() funciona parcialmente:

std::string getMessageName(void) const { std::string typeStr(typeid(*this).name()); delete (typeid(*this).name()); return typeStr; }

Sin embargo, todavía hay algunas pérdidas de memoria. Acabo de notar que anteriormente parecía tener dos filtraciones por llamada (¿quizás debido a que las clases están dentro de un espacio de nombres?). Usando la versión anterior del código, esto se redujo a una fuga por llamada.

Otra solución que parece funcionar es vincular en la versión dinámica de las bibliotecas de MFC (sí, estoy usando MFC, no me juzgue), en lugar de la versión estática.

Tengo un programa en el que, en parte para el registro informativo, obtengo los nombres de algunas clases a medida que se utilizan (específicamente agrego una entrada a un registro que dice a lo largo de las líneas Messages::CSomeClass transmitted to 127.0.0.1 ). Lo hago con un código similar al siguiente:

std::string getMessageName(void) const { return std::string(typeid(*this).name()); }

Y sí, antes de que alguien lo señale, me doy cuenta de que el resultado de typeinfo::name es específico de la implementación.

De acuerdo con MSDN

La función de miembro type_info::name devuelve un const char* a una cadena terminada en nulo que representa el nombre legible por humanos del tipo. La memoria apuntada se almacena en caché y nunca se debe desasignar directamente.

Sin embargo, cuando salgo de mi programa en el depurador, cualquier uso "nuevo" de typeinfo::name() aparece como una pérdida de memoria. Si genero la información para 2 clases, obtengo 2 pérdidas de memoria, y así sucesivamente. Esto sugiere que los datos en caché nunca se liberan.

Si bien esto no es un problema importante, parece desordenado, y después de una larga sesión de depuración podría ocultar fácilmente fugas de memoria genuinas.

Miré a mi alrededor y encontré información útil (una respuesta SO proporciona información interesante sobre cómo se puede implementar typeinfo ), pero me pregunto si esta memoria normalmente debería ser liberada por el sistema, o si hay algo que pueda hacer para "no notar" las fugas cuando se depura.

Tengo un plan de respaldo, que es codificar el método getMessageName y no confiar en typeinfo::name , pero me gustaría saber de todos modos si hay algo que me he perdido.


Acabo de tropezar con este problema tratando de limpiar el registro de VLD . Sí, este es un error conocido , que se soluciona solo en VC11. Existe en versiones anteriores de MSVC incluyendo 2010. Esta falla solo aparece si usa MFC. Si usa MFC como DLL en lugar de biblioteca estática, la pérdida de memoria seguirá existiendo, pero no se detectará.

Hay un caché global de nombres de type_info y no se borra (el extracto de <typeinfo> ):

struct __type_info_node { void *_MemPtr; __type_info_node* _Next; }; extern __type_info_node __type_info_root_node;

La idea es limpiar este caché. Esta función funciona para mí:

#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; } }

Llame a clear_type_info_cache() antes de salir. Puedes registrarlo con atexit

#include <cstdlib> int WinMain(...) { atexit(&clear_type_info_cache); ... }

o llámalo inmediatamente antes de salir de 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; ... }


Otra solución es corregir el problema subyacente. Esto no es realmente una pérdida de memoria, solo un informe falso. Los bloques de memoria asignados a las cadenas tyepinfo () y name () tienen asignado el tipo de bloque incorrecto. Probablemente no sea una buena idea "liberar" esta memoria, ya que el CRT intentará liberarla nuevamente. La buena noticia es que esto finalmente se solucionó en VS2012 (_MSC_VER 1700+).

Como esto solo se aplica a las compilaciones de _DEBUG, la siguiente puede ser una solución más segura. La función _FixTypeInfoBlockUse () debe invocarse como se mencionó anteriormente justo antes de salir del punto de entrada del módulo (principal, WinMain, etc.).

#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)


Las tiendas VS escriben información en una lista vinculada individualmente. El encabezado de esta lista es accesible por una estructura opaca accesible por nombre __type_info_root_node . En realidad, es una estructura SLIST_HEADER.

Win32 API tiene un conjunto de funciones seguras para concurrencia para trabajar con tales estructuras. Para reparar el informe de fugas de memoria En su caso, debe eliminar todos los nodos de esta lista.

#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; }

Actualizado: VLD 2.5.1 no informa pérdidas de memoria en type_info :: name () en VS2015 Update 3.