Buenas,
Cuando escribes más de 15 líneas en c pues te encuentras con estos problemas. En linux he encontrado mtrace que hace más o menos lo que necesito pero me gustaría un programa que detectase memory leaks para windows para mingw.
¿Conocéis alguno?
Muchas gracias.
Un saludo.
yo usaba este:
http://libmss.sourceforge.net/manual.html
es transparente, usas malloc y free como normalmente. instalarlo es meter la linea del include. y al ejecutar el programa se te genera un mss.log con los warning, y tal.
Un ejemplo (poco ilustrativo) del output.
mss.log (http://www.google.es/codesearch?hl=es&q=show:PBYdTlHMiFw:OJOt_iu8eKA:UIaXXCpNHxg&sa=N&ct=rd&cs_p=ftp://ftp.berlios.de/pub/telejano/telejano13sep2003src.zip&cs_f=telejano/mss.log&start=1)
Es poco ilustrativo porque solo tengo 1 malloc, al usar el juego su propio sistema de administracion de memoria.
Ok, tiene buena pinta, le daré un ojo.
Gracias!!
Yo siempre he usado el gestor de memoria de Paul Nettle (administrador del foro de la mitica flipcode):
http://www.paulnettle.com/pub/FluidStudios/MemoryManagers/Fluid_Studios_Memory_Manager.zip
Cita de: "Astat"Yo siempre he usado el gestor de memoria de Paul Nettle (administrador del foro de la mitica flipcode):
http://www.paulnettle.com/pub/FluidStudios/MemoryManagers/Fluid_Studios_Memory_Manager.zip
Yo también y siempre me ha ido muy bien.
Cita de: "vincent"Cita de: "Astat"Yo siempre he usado el gestor de memoria de Paul Nettle (administrador del foro de la mitica flipcode):
http://www.paulnettle.com/pub/FluidStudios/MemoryManagers/Fluid_Studios_Memory_Manager.zip
Yo también y siempre me ha ido muy bien.
Hasta que lo usas con stl :)
CitarHasta que lo usas con stl
Para eso siempre tienes
#include "nommgr.h"
#include <vector>
#include "mmgr.h"
Cita de: "Astat"CitarHasta que lo usas con stl
Para eso siempre tienes
#include "nommgr.h"
#include <vector>
#include "mmgr.h"
claro, pero entonces no tienes control de leaks que es de lo que se trata.
vale, otra:
class pepe {
void* operator new(size_t t);
};
(y no me vale la guarrada del include en medio del .h :))
otra más:
en multithread casca todo lo que quiere y más.
Es una buena librería, pero tiene unos problemas que hay que conocer muy bien antes de usarla.
Y tu que recomiendas ethy?
Cita de: "Pogacha"Y tu que recomiendas ethy?
Yo no recomiendo nada porque solo he usado el que se está comentando y tuve muy malas experiencias por dos razones, una el tema de MT y la otra que las cabeceras estaban muy mal organizadas y se montó un pitote tremento entre stl, speedtree, etc...
Yo creo que esta es buena (o la que usan en quake) o cualquiera siempre que se sepa sus limitaciones porque no hay peor cosa que buscar un problema de temas de memoria.
Yo use la de fluids studios pero me encontre con los mensionados problemas y desistí de la idea.
No suelo tener demasiados problemas con memory leaks, pero cuando ocurren es un infierno encontrarlos. Seria bueno tener una ayuda en el tema.
¿Esta tiene algún problema?
http://libmss.sourceforge.net/manual.html
Desde hace ya varios años que vengo usando el DevPartner (http://www.compuware.com/products/devpartner/visualc.htm), es un producto bastante caro para los que hacen esto por hobby, pero es una herramienta sumamente útil para cualquier persona que se dedica a esto a tiempo completo.
El Visual Leak Detector.
http://dmoulding.googlepages.com/vld
Lo malo es que es sólo para para Visual C++, pero es sencillo y funciona bastante bien.
Cita de: "zheo"El Visual Leak Detector.
http://dmoulding.googlepages.com/vld
Lo malo es que es sólo para para Visual C++, pero es sencillo y funciona bastante bien.
No hay problema si Visual C++ es un compilador estandar de C++. Pues puedes debugear leaks de memoria con una herramienta X, pero luego que realmente tu codigo esta pensado para compilarse con GCC y funcionar en Linux. La libreria detectora de leaks no estara en el binario distribuido. Es solo una herramienta que se usa en el proceso. Por eso, aunque no es muy etico, se podria usar un detector de leaks "shareware" o "trial".
Y no añado mas.
Lo digo porque no se hasta qué punto el VLD puede utilizar extensiones del compilador VC++, y por ello podría ser incompatible con gcc/g++ por ejemplo
Hola,
tambien puedes implementarla tu mismo, en la ultima version de la libreria "multi-todo" que aun no he subido al web tengo una clase que sirve como reutilizador de memoria y depurador.
// garbage.h
// Por David Inclán Blanco
// http://www.davidib.com
// Este codigo esta protegido bajo licencia LGPL
#ifndef _dib_Memory_Garbage
#define _dib_Memory_Garbage
// Incluir cabeceras
#ifdef dib_Windows
#include <conio.h>
#endif
#include "memory.h"
#include "../type/object.h"
#include "../pattern/singleton.h"
#include "../io/log.h"
#define dib_Memory_Garbage_Name "Garbage"
namespace dib
{
namespace Memory
{
/// <summary>Permite reutilizar bloques de memoria previamente asignados acelerando la creacion y destruccion de objetos o zonas de memoria</summary>
/// <remarks>Si se indica dib_Debug se almacenaran en una lista las memorias que estan siendo usadas y de esta manera saber si no se ha liberado alguna de ellas</summary>
class Garbage : public dib::Type::Object
{
private:
/// <summary>Estructura prememoria</summary>
struct Head
{
/// <summary>Tamaño asignado</summary>
unsigned int size;
/// <summary>Numero de usos</summary>
unsigned int uses;
/// <summary>Siguiente memoria</summary>
Head* next;
#ifdef dib_Debug
/// <summary>Memoria anterior (solo se usa en la lista de memorias en uso)</summary>
Head* previous;
/// <summary>Nombre del archivo al que pertenece</summary>
const char* file;
/// <summary>Linea en este archivo</summary>
int line;
#endif
};
public:
/// <summary>Inicializar la clase</summary>
Garbage()
{
// Limpiar la tabla de memorias
Set( this->noUse, 0, sizeof(this->noUse) );
#ifdef dib_Debug
// Indicar que no hay ninguna memoria en uso
this->yesUse = null;
#endif
gLog->Write( dib_Memory_Garbage_Name, false, "Inicializado" );
}
/// <summary>Eliminar la clase</summary>
~Garbage()
{
// Eliminar todas las memorias sin uso
this->Clean( 0 );
#ifdef dib_Debug
// Si esta el modo debug activado mostrar las memorias usadas sin liberar
this->PrintMemoryUseds();
#endif
gLog->Write( dib_Memory_Garbage_Name, false, "Eliminado" );
}
/// <summary>Sumar un uso a una memoria</summary>
/// <param name="ptr">Puntero</param>
/// <remarks>Para eliminar uso se debe de llamar directamente a delete</remarks>
void AddRef( void* ptr )
{
Head* head = ((Head*)ptr) -1;
head->uses++;
}
/// <summary>Crear una nueva zona de memoria</summary>
/// <param name="size">Tamaño</param>
/// <param name="file">Nombre del archivo al que pertenece (solo con dib_Debug)
/// <param name="line">Linea en el archivo (solo con dib_Debug)
/// <returns>Nueva zona de memoria o null si no se ha podido crear</returns>
#ifdef dib_Debug
void* New( unsigned int size, const char* file, int line )
#else
void* New( unsigned int size )
#endif
{
// Mirar si existe alguna memoria en la tabla de memorias sin uso que se ajuste a las necesidades
int index = size % capacity;
Head* ret = *(this->noUse + index);
Head* previous = null;
while( ret != null )
{
if( ret->size == size )
{
// Tiene el mismo tamaño, nos vale perfectamente
if( previous != null )
{
// Esta por el medio
previous->next = ret->next;
}
else
{
// Es el primero
*(this->noUse + index) = ret->next;
}
#ifdef dib_Debug
InsertOnUsedMem( ret, file, line );
#endif
ret->uses = 0;
return (void*)(ret + 1);
}
// Siguiente
previous = ret;
ret = ret->next;
}
// No existe en la tabla de memorias asi que tenemos que crear una nueva
ret = (Head*)dib::Memory::Create( sizeof(Head) + size );
if( ret != null )
{
ret->size = size;
#ifdef dib_Debug
InsertOnUsedMem( ret, file, line );
#endif
ret->uses = 0;
return (void*)(ret + 1);
}
// Error al crear la memoria
return null;
}
/// <summary>Liberar una zona de memoria que ha sido creada con la funcion New de esta clase</summary>
/// <param name="ptr">Puntero a la zona de memoria</param>
void Delete( void* ptr )
{
if( ptr != null )
{
Head* head = ((Head*)ptr) -1;
if( head->uses <= 1 )
{
#ifdef dib_Debug
// Eliminarlo de la lista de las tablas de memoria en uso
if( head->previous != null )
{
// Esta por el medio
head->previous->next = head->next;
if( head->next != null )
{
head->next->previous = head->previous;
}
}
else
{
// Esta al inicio
this->yesUse = head->next;
if( this->yesUse != null )
{
this->yesUse->previous = null;
}
}
#endif
// Insertarlo al inicio de la tabla de memorias sin uso
unsigned int index = head->size % capacity;
head->next = *(this->noUse + index);
*(this->noUse + index) = head;
}
else
{
// Un uso menos
head->uses--;
}
}
}
/// <summary>Eliminar toda las zonas de memoria que no estan siendo usadas<summary>
/// <param name="size">Tamaño minimo de las zonas de memoria a eliminar</param>
/// <remarks>
/// Esta funcion elimina las memorias que no esten usadas, como parametro extra se le puede indicar que busque aquellos que superen o sean iguales al un tamaño dado, las demas
/// zonas de memoria no seran eliminadas, esto nos permite optimizar bastante ya que normalmente las zonas de memoria pequeñas suelen ser clases, variables normales, etc mientras
/// que las zonas de memoria grandes suelen ser imagenes, sonidos, etc que muy rara vez se reaprovecharan.
/// </reamrks>
void Clean( unsigned int size = 4096 )
{
Head* next;
// Recorrer toda la tabla hash
for( int n = 0; n < capacity; n++ )
{
// Recorrer la lista
while( this->noUse[n] != null )
{
if( this->noUse[n]->size < size )
{
// Siguiente
this->noUse[n] = this->noUse[n]->next;
}
else
{
next = this->noUse[n]->next;
// Liberar esta zona de memoria
dib::Memory::Delete( (void*)this->noUse[n] );
this->noUse[n] = next;
}
}
}
}
#ifdef dib_Debug
/// <summary>Mostrar las memorias que estan siendo usadas y no han sido liberadas</summary>
/// <param name="sizeSample">Tamaño de ejemplo a mostrar de la memoria</param>
void PrintMemoryUseds( unsigned int sizeSample = 32 )
{
if( this->yesUse != null )
{
Head* current = this->yesUse;
gLog->Write( dib_Memory_Garbage_Name, true, "Memoria sin liberar:" );
char* sample = (char*)dib::Memory::Create( sizeSample );
unsigned int size;
while( current != null )
{
// Copiar un ejemplo de la memoria
size = current->size < sizeSample ? current->size : sizeSample -1;
Copy( sample, (const void*)(current+1), size );
sample[size] = '\0';
// Mostrarlo
gLog->Write( null, false, "%s:%i (%i bytes / usado: %i): %s\n", current->file, current->line, current->size, current->uses, sample );
// Siguiente
current = current->next;
}
dib::Memory::Delete( (void*)sample );
printf( "Garbage: Hay memoria sin liberar\n" );
#ifdef dib_Windows
getch();
#endif
}
}
#endif
private:
#ifdef dib_Debug
/// <summary>Insertar una memoria al inicio de la lista de memorias en uso</summary>
/// <param name="head">Memoria a insertar</param>
/// <param name="file">Nombre del archivo al que pertenece (solo con dib_Debug)
/// <param name="line">Linea en el archivo (solo con dib_Debug)
void InsertOnUsedMem( Head* head, const char* file, int line )
{
head->file = file;
head->line = line;
head->previous = null;
head->next = this->yesUse;
if( this->yesUse != null )
{
this->yesUse->previous = head;
}
this->yesUse = head;
}
#endif
/// <summary>Enumeraciones</summary>
enum
{
/// <summary>Capacidad de las tablas hash en la clase</summary>
capacity = 16381,
};
/// <summary>Tabla hash donde se almacenan las zonas de memoria que NO estan siendo usadas</summary>
Head* noUse[capacity];
#ifdef dib_Debug
/// <summary>Lista enlazada con las zonas de memoria que si estan siendo usadas</summary>
Head* yesUse;
#endif
};
}
}
/// <summary>Instancia unica de la clase garbage</summary>
dib::Pattern::Singleton<dib::Memory::Garbage > gGarbage( true );
#ifdef dib_Debug
/// <summary>Operador new global</summary>
/// <param name="size">Tamaño de la memoria</param>
/// <param name="file">Nombre del fichero asociado a esta memoria</param>
/// <param name="line">Linea asociada del fichero</param>
/// <returns>Puntero a la memoria</returns>
void* __cdecl operator new( unsigned int size, const char* file, int line )
{
return gGarbage->New( size, file, line );
}
#define new new( __FILE__, __LINE__ )
#else
/// <summary>Operador new global</summary>
/// <param name="size">Tamaño de la memoria</param>
/// <returns>Puntero a la memoria</returns>
void* __cdecl operator new( unsigned int size )
{
return gGarbage->New( size );
}
#endif
/// <summary>Operador delete global</summary>
/// <param name="pointer">Puntero a la memoria que se quiere borrar</param>
void __cdecl operator delete( void* pointer )
{
return gGarbage->Delete( pointer );
}
#endif _dib_Memory_Garbage
Parece muy complicado al principio, pero realmente es muy sencillo de leer el codigo si se le dedica unos minutos.
El modo reutilizador de memoria funciona con todos los compiladores que he probado (gcc, vc++), el reutilizador de memoria + depurador solo lo he probado con el vc++, pero si existen las constantes __FILE__ y __LINE__ no deberia de dar problemas.
Tambien existe otra clase que aun no he probado mucho ya que la hice casi al final de terminar la libreria, es una clase de punteros "inteligentes" que libera la memoria solo cuando es necesario (numero de usos), realmente es complementaria, es decir, no es requerida para que funcione la clase del reutilizador de memoria + depurador.
// ptr.h
// Por David Inclán Blanco
// http://www.davidib.com
// Este codigo esta protegido bajo licencia LGPL
#ifndef _dib_Memory_ptr
#define _dib_Memory_ptr
#include "garbage.h"
//namespace dib
//{
// namespace Memory
// {
/// <summary>Clase que permite trabajar con punteros inteligentes</summary>
template <class TYPE> class ptr
{
public:
/// <summary>Inicializar el puntero con null</summary>
ptr()
{
this->mem = null;
}
/// <summary>Inicializar el puntero con una zona de memoria creada con new</summary>
/// <param name="mem">Memoria</param>
ptr( TYPE* mem )
{
this->mem = null;
this->SetMem( mem );
}
/// <summary>Indicar la memoria a usar con este puntero</summary>
/// <param name="mem">Memoria</param>
ptr& operator = ( TYPE* mem )
{
this->SetMem( mem );
return *this;
}
/// <summary>Indicar la memoria a usar con este puntero</summary>
/// <param name="pointer">Clase puntero</param>
ptr& operator = ( ptr& pointer )
{
this->SetMem( pointer.mem );
return *this;
}
/// <summary>Obtener contenido del puntero</summary>
void* operator * ()
{
return this->mem;
}
private:
/// <summary>Indicar la memoria</summary>
/// <param name="mem">Memoria</param>
void SetMem( TYPE* mem )
{
// Quitar un uso
delete this->mem;
if( mem != null )
{
gGarbage->AddRef( mem );
this->mem = mem;
}
}
/// <summary>Memoria en uso</summary>
TYPE* mem;
};
// }
//}
#endif
Saludos[/code]
#define new new( __FILE__, __LINE__ )
Estas seguro que esto anda?
O es una version vieja y no te diste cuenta o no se ...