Muistidebuggeri

weicco 11.10.03 13:41

Luokka, jonka avulla voi kätevästi debugata muistivuotoja.

 Tekstiversio  Arvo: 2 (4 ääntä)  Äänestä: +  -
/*
 * Headeri.
 * Muista laittaa jotain #ifndef _BLAA_ #define _BLAA_ #endif
 * härpäkkeitä headerin ympärille
 */


#include <stdlib.h>
#include <string.h>
#include <stdio.h>

// Use these macros to allocate and free memory
// Unless you want to write file names and line index yourself
#ifdef _DEBUG
#define MALLOC(CWMemoryObject, BlockLength) CWMemoryObject->Allocate(BlockLength, __FILE__, __LINE__)
#define FREE(CWMemoryObject, MemoryBlock) CWMemoryObject->Free(MemoryBlock, __FILE__, __LINE__)
#else
#define MALLOC(CWMemoryObject, BlockLength) CWMemoryObject->Allocate(BlockLength, "na", -1)
#define FREE(CWMemoryObject, MemoryBlock) CWMemoryObject->Free(MemoryBlock, "na", -1)
#endif

/**
 * @class CWMemory
 * @brief Memory handling class. Helps tracking down memory leaks.
 */

class CWMemory 
{
private:
        /** Private constructor */
        CWMemory(unsigned int blocks);
        /** Private destructor */
        virtual ~CWMemory();

public:
        /** Create new CWMemory object. Only one instance per process is allowed. */
        static CWMemory *Create(unsigned int blocks = 10);
        /** Destroys instance */
        void Destroy() { delete this; }

        /** Allocates block of memory */
        void *Allocate(const unsigned long length, char *file, int line);
        /** Frees previously allocated memory block */
        void Free(void *memblck, const char *file, int line);

        /** Cleans up internal database */
        void Flush();

        /** Saves memory allocation info to file */
        void ToFile(FILE *fOut) const;
private:
        struct _mem_object_t {
                _mem_object_t(void *d, char *f, int r, int l) {
                        data = d; data_length = l; alloc_file = strdup(f);
                        alloc_row = r; next = NULL; freed_file = NULL; freed_row = -1; }

                struct _mem_object_t *next;
                void *data;
                int data_length;
                char *alloc_file, *freed_file;
                int alloc_row, freed_row;
        };

        static bool m_IsInstance;
        struct _mem_object_t *m_List;

        // List handling stuff
        void Push(struct _mem_object_t *p);
        struct _mem_object_t *Find(void *mem) const;
        void Remove(struct _mem_object_t *p);
};

/*
 * CPP tiedosto.
 * Mmuista includata ylempi headeri mukaan.
 */

bool CWMemory::m_IsInstance = false;

CWMemory::CWMemory(unsigned int blocks)
{
        m_List = NULL;
}

CWMemory::~CWMemory()
{
        m_IsInstance = false;
        while (m_List) {
                struct _mem_object_t *tmp = m_List;
                m_List = m_List->next;
                free(tmp->alloc_file);
                free(tmp->freed_file);
                free(tmp);
        }
}

CWMemory *CWMemory::Create(unsigned int blocks/* = 10*/)
{
        if (m_IsInstance) return NULL;
        m_IsInstance = true;

        CWMemory *This = new CWMemory(blocks);

        return This;
}

void *CWMemory::Allocate(const unsigned long length, char *file, int line)
{
        struct _mem_object_t *mem = Find(NULL);
       
        if (mem == NULL) {
                mem = new struct _mem_object_t(malloc(length), file, line, length);
                Push(mem);
        }
        else {
                mem->data = malloc(length);
                free(mem->alloc_file);
                mem->alloc_file = strdup(file);
                mem->alloc_row = line;
        }

        return mem->data;
}

void CWMemory::Free(void *memblck, const char *file, int line)
{
        struct _mem_object_t *tmp = Find(memblck);
        if (tmp == NULL) return;

        free(tmp->data);
        tmp->data = NULL;

        if (tmp->freed_file) free(tmp->freed_file);
        tmp->freed_file = strdup(file);
        tmp->freed_row = line;
}

void CWMemory::Flush()
{
        struct _mem_object_t *tmp = NULL;
        while ((tmp = Find(NULL))) {
                Remove(tmp);
                if (tmp->alloc_file) free(tmp->alloc_file);
                if (tmp->freed_file) free(tmp->freed_file);
                delete tmp;
        }
}

void CWMemory::ToFile(FILE *fOut) const
{
        fprintf(fOut, "Syntax:\n");
        fprintf(fOut, "File where allocated | Line where allocated | Amount | File where freed | Line where freed\n");

        struct _mem_object_t *tmp = m_List;
        while (tmp) {
                fprintf(fOut, "%s | %i | %i | %s | %i\n",
                        tmp->alloc_file, tmp->alloc_row, tmp->data_length,
                        tmp->freed_file, tmp->freed_row);

                tmp = tmp->next;
        }
}

void CWMemory::Push(struct _mem_object_t *p)
{
        struct _mem_object_t *tmp = m_List;
        if (tmp == NULL) {
                m_List = p;
                return;
        }

        while (tmp->next) tmp = tmp->next;
        tmp->next = p;
}

struct CWMemory::_mem_object_t *CWMemory::Find(void *mem) const
{
        struct _mem_object_t *tmp = m_List;
        if (tmp) {
                do {
                        if (tmp->data == mem) return tmp;
                        tmp = tmp->next;
                } while (tmp);
        }

        return NULL;
}

void CWMemory::Remove(struct _mem_object_t *p)
{
        struct _mem_object_t *tmp = m_List;
        struct _mem_object_t *prv = NULL;

        while (tmp) {
                if (tmp == p) {
                        if (prv) prv->next = tmp->next;
                        else m_List = tmp->next;
                        break;
                }
                tmp = tmp->next;
        }
}

/*
 * Esimerkkikoodipätkä.
 * Muista includata headeri, jos laitat koodit eri tiedostoihin.
 */

int main(void)
{
        CWMemory *pMemory = CWMemory::Create(20);
        void *p1 = MALLOC(pMemory, 100);
        void *p2 = MALLOC(pMemory, 100);

        FREE(pMemory, p1);
        FREE(pMemory, p2);

        FILE *p = fopen("out.log", "w");
        pMemory->ToFile(p);
        fclose(p);

        pMemory->Flush();

        pMemory->Destroy();

        return 0;
}

weicco 13:43 11.10.03 
Karvalakkiversio. Puuttuu varmaan n+1 toimintoa, mutta tämän tarkoitus onkin havainnollistaa, kuinka metsästää tiukassa olevia muistivuotoja. Tämän koodin edeltäjä pelasti minut ainakin parista tiukasta paikasta.
psd 02:12 16.10.03 
Eipä tuota voi käyttää kuin perustyypeille. Luokille vaatisi placement new:n käyttöä ja destructoreiden manuaalista kutsumista. C++:lla muistimanagerin toteuttaminen käytännössä vaatii operator new/deleten korvaamista. Tämän saa tehtyä käyttäjälle näkymättömästi.

Oma säätöni löytyy osoitteesta http://www.cs.helsinki.fi/u/hiekkama/memory_manager.zip