Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / C++

Session of low-level optimization of memory usage in C++ programs with total exposure

,
Rate me:
Please Sign up or sign in to vote.
5.00/5 (13 votes)
22 Jun 2009CPOL7 min read 39.6K   246   44  
In this article, we will try to make our algorithms work faster using the methods of low-level optimization of memory allocation in C++.
#ifndef ARENA_H
#define ARENA_H

#include "alloc\crt_stl_allocators.h"
#include "assert.h"
#include "cmnFastObjects.h"

namespace utils
{

struct IArena
{
    virtual ~IArena(){}
    virtual void * Allocate(size_t size) = 0;
    virtual void * AllocateNoThrow(size_t size) = 0;
    virtual void Deallocate(void * p) = 0;
    virtual void Clear() = 0;
};


struct IArenaGlobalCounter
{
    virtual ~IArenaGlobalCounter(){}
    // debug api
    virtual void ChangeGlobalCount(int iValue)=0;
    virtual long GetGlobalCount() const =0;
};

struct IArenaContext
{
    virtual ~IArenaContext(){}
    // arena api
    virtual IArena * GetArena() const=0;
    virtual void SetArena(IArena * pArena)=0;
};

const int g_iMaxArenaContextSizeInBytes = 16;

typedef utils::CFastObject<g_iMaxArenaContextSizeInBytes, IArenaContext> ArenaContext_type;

struct IArenaProvider
{
    virtual ~IArenaProvider(){}
    // item api
    virtual void QueryThreadAssociatedItem(ArenaContext_type * pContext)=0;
};

void Arena_InitLib(IArenaProvider * pProvider, //  IN, OPTIONAL
                   IArenaGlobalCounter * pCounter=0); //  IN, OPTIONAL

void Arena_UnregisterLib();

class CArenaLib
{
    CArenaLib(const CArenaLib &);
    CArenaLib & operator =(const CArenaLib &);
public:
    CArenaLib(IArenaProvider * pProvider, //  IN, OPTIONAL
              IArenaGlobalCounter * pCounter=0)
    {
        Arena_InitLib(pProvider, pCounter);
    }
    ~CArenaLib()
    {
        Arena_UnregisterLib();
    }
};

void RegisterArena(IArena * pArena);
IArena * ExchangeArena(IArena * pArena);
void UnregisterArena();
void Arena_ChangeGlobalCount(int iDelta);
long Arena_GetGlobalCount();

// base template CArena
template<class BufferType>
class CArena:public IArena
{
    BufferType m_buffer;
    size_t m_iIndex;
    
    CArena(const CArena &);
    CArena & operator =(const CArena &);

protected:

#ifdef _DEBUG
    typedef utils::crt_set<void *>::result SetType;
    SetType m_ptrSet;
    void DbgRegisterAllocate(void * pData)
    {
        std::pair<typename SetType::iterator, bool> res = m_ptrSet.insert(pData);
        if (!res.second)
        {
            abort(); // "DBG: Cannot unregister ptr"
        }
    }
    void DbgRegisterDeallocate(void * pData)
    {
        typename SetType::iterator it = m_ptrSet.find(pData);
        if (it == m_ptrSet.end())
            abort(); // "DBG: Cannot unregister ptr"
        else
            m_ptrSet.erase(it);
    }
    void DbgCheck()
    {
        if (!m_ptrSet.empty())
        {
            abort();
        }
    }
#else
    void DbgRegisterAllocate(void * ) {}
    void DbgRegisterDeallocate(void * ){}
    void DbgCheck() {}
#endif

    // interface for childs
    size_t GetIndex() { return m_iIndex; }
    void SetIndex(size_t index) { m_iIndex = index; }

public:
    CArena() : m_iIndex (0)
    {
        Arena_ChangeGlobalCount(1);
    }
    template<class ParamType>
    CArena(ParamType param) : m_buffer(param), m_iIndex (0) 
    {
        Arena_ChangeGlobalCount(1);
    }
    ~CArena()
    {
        Clear();
        Arena_ChangeGlobalCount(-1);
    }
    void * Allocate(size_t size)
    {
        const size_t bufSize = m_buffer.GetTotalSize();
        if (bufSize <= m_iIndex)
            throw std::bad_alloc("bad_alloc");
        if (bufSize - m_iIndex < size)
            throw std::bad_alloc("bad_alloc");

        void * pResult = m_buffer.GetPtr() + m_iIndex;
        m_iIndex += size;

        DbgRegisterAllocate(pResult);
        return pResult;
    }
    virtual void * AllocateNoThrow(size_t size) 
    {
        const size_t bufSize = m_buffer.GetTotalSize();
        if (bufSize <= m_iIndex)
            return 0;
        if (bufSize - m_iIndex < size)
            return 0;

        void * pResult = m_buffer.GetPtr() + m_iIndex;
        m_iIndex += size;

        DbgRegisterAllocate(pResult);
        return pResult;
    }
    void Deallocate(void * p)
    {
        DbgRegisterDeallocate(p);
    }
    void Clear()
    {
        DbgCheck();
        m_iIndex = 0;
    }
    // user api
    BufferType * GetBuffer() { return &m_buffer; }
    const BufferType * GetBuffer() const { return &m_buffer; }
};

// buffers
template<size_t iMaxSize>
class CConstBuffer
{
    char m_buffer[iMaxSize];
public:
    char * GetPtr() { return m_buffer; }
    size_t GetTotalSize() { return iMaxSize; }
};
class CDynamicBuffer
{
    typedef utils::crt_vector<char>::result Buffer_type;
    Buffer_type m_buffer;
public:
    CDynamicBuffer()
    {
    }
    CDynamicBuffer(size_t size)
        : m_buffer( size )
    {
    }
    char * GetPtr() { return &m_buffer.front(); }
    size_t GetTotalSize() { return m_buffer.size(); }
    void Resize(size_t size) { return m_buffer.resize(size); }  
};

template<size_t iMaxArenaSize>
class CConstArena:public CArena<CConstBuffer<iMaxArenaSize> >
{
};

class CDynamicArena:public CArena<CDynamicBuffer>
{
public:
    CDynamicArena()
        : CArena<CDynamicBuffer>(0)
    {
    }
    CDynamicArena(size_t size)
        : CArena<CDynamicBuffer>(size)
    {
    }
};

// class CAutoCleaner helps to clean IArena at the end of iteration
class CAutoCleaner
{
    IArena * m_pArena;

    CAutoCleaner(const CAutoCleaner &);
    CAutoCleaner&operator = (const CAutoCleaner &);
public:
    CAutoCleaner(IArena * pArena)
        : m_pArena(pArena)
    {
    }
    ~CAutoCleaner()
    {
        m_pArena->Clear();
    }
};


// class CExclusiveAutoArena provides IArena exclusive registration procedure
class CExclusiveAutoArena
{
    IArena * m_pArena;

    CExclusiveAutoArena(const CExclusiveAutoArena&);
    CExclusiveAutoArena&operator = (const CExclusiveAutoArena&);
public:
    CExclusiveAutoArena(IArena * pArena)
        : m_pArena(pArena)
    {
        RegisterArena( pArena );
    }
    ~CExclusiveAutoArena()
    {
        UnregisterArena();
    }
};

// class CExclusiveAutoArena provides IArena registration procedure
class CAutoArena
{
    IArena * m_pArena;
    IArena * m_pOldArena;

    CAutoArena(const CAutoArena&);
    CAutoArena&operator = (const CAutoArena&);
public:
    CAutoArena(IArena * pArena)
        : m_pArena(pArena), m_pOldArena(0)
    {
        m_pOldArena = ExchangeArena( pArena );
    }
    ~CAutoArena()
    {
        IArena * pCurrentArena = ExchangeArena( m_pOldArena );
        &pCurrentArena;
        assert(pCurrentArena == m_pArena);
    }
};


// Arena API
void * Arena_Alloc(size_t size);
void * Arena_AllocNoThrow(size_t size);
void Arena_Free(void * p);

} // utils


#define ARENA_DEFINE_GLOBAL_OPERATORS        \
    void  * __cdecl operator new(size_t size) \
    {\
        return utils::Arena_Alloc(size);\
        \
    }\
    void  * __cdecl operator new[](size_t size)\
    {\
        return utils::Arena_Alloc(size);\
    }\
    void  __cdecl operator delete[](void* pData)\
    {\
        utils::Arena_Free(pData);\
    }\
    void  __cdecl operator delete(void* pData)\
    {\
        utils::Arena_Free(pData);\
    }\
    void  * __cdecl operator new(size_t size,const std::nothrow_t&) \
    {\
        return utils::Arena_AllocNoThrow(size);\
        \
    }\
    void  * __cdecl operator new[](size_t size,const std::nothrow_t&)\
    {\
        return utils::Arena_AllocNoThrow(size);\
    }\
    void  __cdecl operator delete[](void* pData,const std::nothrow_t&)\
    {\
        utils::Arena_Free(pData);\
    }\
    void  __cdecl operator delete(void* pData,const std::nothrow_t&)\
    {\
        utils::Arena_Free(pData);\
    }

#define ARENA_DEFINE_CLASS_OPERATORS        \
    static void* operator new(std::size_t size)\
    {\
        return utils::Arena_Alloc( size );\
    }\
    static void* operator new(std::size_t size, std::nothrow_t) \
    {\
        return utils::Arena_AllocNoThrow( size );\
    }\
    static void operator delete( void * address )\
    {\
        return utils::Arena_Free( address );\
    }\
    void operator delete( void * address , std::nothrow_t)\
    {\
        return utils::Arena_Free( address );\
    }

#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Apriorit Inc.
United States United States
ApriorIT is a software research and development company specializing in cybersecurity and data management technology engineering. We work for a broad range of clients from Fortune 500 technology leaders to small innovative startups building unique solutions.

As Apriorit offers integrated research&development services for the software projects in such areas as endpoint security, network security, data security, embedded Systems, and virtualization, we have strong kernel and driver development skills, huge system programming expertise, and are reals fans of research projects.

Our specialty is reverse engineering, we apply it for security testing and security-related projects.

A separate department of Apriorit works on large-scale business SaaS solutions, handling tasks from business analysis, data architecture design, and web development to performance optimization and DevOps.

Official site: https://www.apriorit.com
Clutch profile: https://clutch.co/profile/apriorit
This is a Organisation

33 members

Written By
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions