Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Memory Leaks

Iniciado por misscelan, 03 de Diciembre de 2007, 04:43:43 PM

« anterior - próximo »

zupervaca

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]

Pogacha

#define new new( __FILE__, __LINE__ )

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






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.