Foros - Stratos

Programadores => General Programadores => Mensaje iniciado por: misscelan en 03 de Diciembre de 2007, 04:43:43 PM

Título: Memory Leaks
Publicado por: misscelan en 03 de Diciembre de 2007, 04:43:43 PM
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.
Título: Re: Memory Leaks
Publicado por: Tei en 03 de Diciembre de 2007, 05:31:18 PM
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.
Título: Memory Leaks
Publicado por: misscelan en 03 de Diciembre de 2007, 08:55:35 PM
Ok, tiene buena pinta, le daré un ojo.

Gracias!!
Título: Memory Leaks
Publicado por: Astat en 04 de Diciembre de 2007, 10:50:52 AM
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
Título: Memory Leaks
Publicado por: vincent en 04 de Diciembre de 2007, 12:07:14 PM
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.
Título: Memory Leaks
Publicado por: ethernet en 04 de Diciembre de 2007, 02:51:16 PM
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 :)
Título: Memory Leaks
Publicado por: Astat en 04 de Diciembre de 2007, 10:19:55 PM
CitarHasta que lo usas con stl

Para eso siempre tienes

#include "nommgr.h"
#include <vector>
#include "mmgr.h"
Título: Memory Leaks
Publicado por: ethernet en 04 de Diciembre de 2007, 11:30:26 PM
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.
Título: Memory Leaks
Publicado por: Pogacha en 06 de Diciembre de 2007, 04:05:18 AM
Y tu que recomiendas ethy?
Título: Memory Leaks
Publicado por: ethernet en 06 de Diciembre de 2007, 02:24:36 PM
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.
Título: Memory Leaks
Publicado por: Pogacha en 06 de Diciembre de 2007, 03:19:08 PM
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
Título: Memory Leaks
Publicado por: Pablo Zurita en 06 de Diciembre de 2007, 06:47:31 PM
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.
Título: Memory Leaks
Publicado por: zheo en 31 de Diciembre de 2007, 12:15:55 AM
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.
Título: Memory Leaks
Publicado por: Tei en 31 de Diciembre de 2007, 10:01:26 AM
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.
Título: Memory Leaks
Publicado por: zheo en 31 de Diciembre de 2007, 12:34:33 PM
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
Título: Memory Leaks
Publicado por: zupervaca en 02 de Enero de 2008, 07:27:15 PM
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]
Título: Memory Leaks
Publicado por: Pogacha en 03 de Enero de 2008, 01:50:57 AM
#define new new( __FILE__, __LINE__ )

Estas seguro que esto anda?
O es una version vieja y no te diste cuenta o no se ...