zoukankan      html  css  js  c++  java
  • MemMan 1.0.0.1 Released!

    /**************************************************
     *
     * MemMan 1.0.0.1
     *
     * Copyright (C) 2007 - 2008 by Len3d
     * All rights reserved.
     *
     ************************************************
    */


    #ifndef __MEM_MAN__
    #define __MEM_MAN__



    #define DEFAULT_MEMORY_ALIGN    16        //    default memory aligment set to this size
    #define ALIGN_DEF                __declspec( align( DEFAULT_MEMORY_ALIGN ) )


    typedef 
    int    (*FreeContentFunc)( void *object, UINT requested_size, UINT & ref_count );    //    can't be member function of a class



    #pragma pack(push,
    1)



    class MemoryAllocator {        //    memory allocator, takes charge of all system operations, also limits the usage of memory
    private:
        typedef UINT    MemoryHeaderBias;    
    //    biased value type of memory header

        
    //    elements of the memory priority queue, keep track of all memory blocks

        
    class MemoryHeader {
        
    public:
            FORCEINLINE MemoryHeader( UINT prior, 
    void *obj, FreeContentFunc func, UINT al )
            
    {
                lchild 
    = rchild = parent = NULL;
                priority 
    = prior;
                
    object = obj;
                free_func 
    = func;
                locked 
    = TRUE;    //    we lock immediately after allocation
                align = al;
                ref_count 
    = 1;    //    assume one block references this header at beginning
                bias = sizeof(MemoryHeader);
                bfact 
    = 0;
            }


            
    //    we don't need a deconstructor for this class

            FORCEINLINE 
    void    lock()
            
    {
                locked 
    = TRUE;
            }


            FORCEINLINE 
    void    unlock()
            
    {
                locked 
    = FALSE;
            }


            FORCEINLINE 
    void    create_child( MemoryHeader *key )
            
    {
                
    if( key->priority < priority )
                
    {
                    
    if( lchild )
                        lchild
    ->create_child( key );
                    
    else
                    
    {
                        lchild 
    = key;
                        lchild
    ->parent = this;
                    }

                }

                
    else
                
    {
                    
    if( rchild )
                        rchild
    ->create_child( key );
                    
    else
                    
    {
                        rchild 
    = key;
                        rchild
    ->parent = this;
                    }

                }

            }


            FORCEINLINE 
    bool    search_memory( UINT search_size, int search_align, void * & search_result, 
                                                
    void *obj, FreeContentFunc func )
            
    {
                
    if( lchild && lchild->search_memory( search_size, search_align, search_result, obj, func ) )
                    
    return true;

                
    if( align == search_align && free_content( search_size ) )
                
    {
                    search_result 
    = get_memory();

                    
    object = obj;    //    update the attributes of the memory block
                    free_func = func;

                    
    return true;
                }


                
    if( rchild && rchild->search_memory( search_size, search_align, search_result, obj, func ) )
                    
    return true;

                
    return false;
            }


            FORCEINLINE 
    void    *get_memory()    //    the allocated memory block
            {
                
    return ((char *)this + sizeof(MemoryHeader));
            }


            FORCEINLINE 
    void    dec_ref_count()    //    decrease the reference count
            {
                
    -- ref_count;
            }


            FORCEINLINE UINT    get_ref_count()    
    //    the reference count
            {
                
    return ref_count;
            }


            
    //    try to free some content of the object for requested size,
            
    //    update the reference count and return the size of the freed memory
            FORCEINLINE int        free_content( UINT requested_size )
            
    {
                
    if!locked && free_func && object )
                    
    return free_func( object, requested_size, ref_count );
                
    else
                    
    return 0;
            }


        
    public:
            ALIGN_DEF 
    struct {    //    48 Byte aligned including the header bias
                MemoryHeader        *lchild,    //    left child, right child and parent
                                    *rchild,
                                    
    *parent;
                UINT                priority;    
    //    priority for sorting the memory blocks
                void                *object;    //    the object for which the memory was allocated
                FreeContentFunc        free_func;    //    function to free the content of the object for requested size,
                                                
    //    memory blocks without this function will be restored to memory-mapped files.
                int                    locked;        //    this memory block was locked by a thread
                int                    bfact;        //    balance factor of the AVL tree
                UINT                align;        //    aligment of the allocated memory should match
                UINT                ref_count;    //    how many blocks reference this header
                UINT                pad;        //    padded to 48 Byte, no use
                MemoryHeaderBias    bias;        //    the header bias
            }
    ;
        }
    ;

    public:
        MemoryAllocator( UINT max_size )    
    //    max allowed memory usage
        {
            allocated_size 
    = 0;
            available_size 
    = max_size;

            queue 
    = NULL;
            aligned_queue 
    = NULL;
        }


        
    ~MemoryAllocator()
        
    {
            dealloc_header( queue );
            dealloc_aligned_header( aligned_queue );
        }


        FORCEINLINE 
    void    *alloc( UINT size, UINT priority, 
                                    
    void *object, FreeContentFunc free_func )
        
    {
            
    if( size == 0 )
            
    {
                
    return NULL;
            }

            
    else if( size > available_size )        //    searching has the complexity of O(N)
            {
                
    void    *ptr = NULL;

                
    if( queue && queue->search_memory( size, 0, ptr, object, free_func ) )
                    
    return ptr;
                
    else
                    
    return NULL;    //    the system has run out of memory
            }

            
    else    //    the complexity is O(logN)
            {
                allocated_size 
    += ( sizeof(MemoryHeader) + size );
                available_size 
    -= ( sizeof(MemoryHeader) + size );

                MemoryHeader    
    *elem;

                
    //    allocate a block
                elem = new (sys_alloc( sizeof(MemoryHeader) + size )) MemoryHeader( priority, object, free_func, 0 );

                
    if( queue )
                    queue
    ->create_child( elem );    //    insert the node
                else
                    queue 
    = elem;    //    be the root

                
    return elem->get_memory();
            }

        }


        FORCEINLINE 
    void    *aligned_alloc( UINT size, UINT priority, 
                                            
    void *object, FreeContentFunc free_func, 
                                            UINT align 
    = DEFAULT_MEMORY_ALIGN )
        
    {
            
    if( size == 0 )
            
    {
                
    return NULL;
            }

            
    else if( size > available_size )        //    searching has the complexity of O(N)
            {
                
    void    *ptr = NULL;

                
    if( aligned_queue && aligned_queue->search_memory( size, align, ptr, object, free_func ) )
                    
    return ptr;
                
    else
                    
    return NULL;    //    the system has run out of memory
            }

            
    else    //    the complexity is O(logN)
            {
                allocated_size 
    += ( sizeof(MemoryHeader) + size );
                available_size 
    -= ( sizeof(MemoryHeader) + size );

                MemoryHeader    
    *elem;

                
    //    allocate an aligned block
                elem = new (sys_aligned_alloc( sizeof(MemoryHeader) + size, align )) MemoryHeader( priority, object, free_func, align );

                
    if( aligned_queue )
                    aligned_queue
    ->create_child( elem );    //    insert the node
                else
                    aligned_queue 
    = elem;    //    be the root

                
    return elem->get_memory();
            }

        }


        
    //    a lock must be used before the object being deallocated, the complexity is O(1)
        
        FORCEINLINE 
    void    lockvoid *ptr )
        
    {
            
    if( ptr )
            
    {
                MemoryHeader    
    *header = get_memory_header( ptr );

                header
    ->lock();
            }

        }


        FORCEINLINE 
    void    unlock( void *ptr )
        
    {
            
    if( ptr )
            
    {
                MemoryHeader    
    *header = get_memory_header( ptr );

                header
    ->unlock();
            }

        }


        
    //    deallocating has the complexity of O(logN)

        FORCEINLINE 
    void    dealloc( void *ptr, UINT size )
        
    {
            
    if( ptr )
            
    {
                MemoryHeader    
    *header, *node, *parent;

                header 
    = get_memory_header( ptr );

                header
    ->dec_ref_count();

                
    if( header->get_ref_count() != 0 )    //    still have objects reference this
                    return;

                parent 
    = header->parent;

                
    if( header->lchild && header->rchild )    //    has left child and right child
                {
                    node 
    = find_rightmost_child( header->lchild );

                    
    //    rebuild the links
                    if( node != header->lchild )
                    
    {
                        node
    ->parent->rchild = node->lchild;
                        
    if( node->lchild )
                            node
    ->lchild->parent = node->parent;

                        node
    ->lchild = header->lchild;
                        node
    ->lchild->parent = node;
                    }


                    node
    ->rchild = header->rchild;
                    node
    ->rchild->parent = node;
                    node
    ->parent = parent;

                    
    if( parent )    //    has parent
                    {
                        
    if( parent->lchild == header )
                            parent
    ->lchild = node;
                        
    else if( parent->rchild == header )
                            parent
    ->rchild = node;
                    }

                    
    else    //    it's the root
                    {
                        queue 
    = node;
                    }

                }

                
    else if( header->lchild )    //    has only left child
                {
                    
    //    rebuild the links
                    node = header->lchild;
                    node
    ->parent = parent;

                    
    if( parent )    //    has parent
                    {
                        
    if( parent->lchild == header )
                            parent
    ->lchild = node;
                        
    else if( parent->rchild == header )
                            parent
    ->rchild = node;
                    }

                    
    else    //    it's the root
                    {
                        queue 
    = node;
                    }

                }

                
    else if( header->rchild )    //    has only right child
                {
                    
    //    rebuild the links
                    node = header->rchild;
                    node
    ->parent = parent;

                    
    if( parent )    //    has parent
                    {
                        
    if( parent->lchild == header )
                            parent
    ->lchild = node;
                        
    else if( parent->rchild == header )
                            parent
    ->rchild = node;
                    }

                    
    else    //    it's the root
                    {
                        queue 
    = node;
                    }

                }

                
    else    //    has no child
                {
                    
    if( parent )    //    has parent
                    {
                        
    if( parent->lchild == header )
                            parent
    ->lchild = NULL;
                        
    else if( parent->rchild == header )
                            parent
    ->rchild = NULL;
                    }

                    
    else    //    it's the root, clear it
                    {
                        queue 
    = NULL;
                    }

                }


                allocated_size 
    -= ( sizeof(MemoryHeader) + size );
                available_size 
    += ( sizeof(MemoryHeader) + size );

                sys_dealloc( header );    
    //    deallocate the block
            }

        }


        FORCEINLINE 
    void    aligned_dealloc( void *ptr, UINT size )
        
    {
            
    if( ptr )
            
    {
                MemoryHeader    
    *header, *node, *parent;

                header 
    = get_memory_header( ptr );

                header
    ->dec_ref_count();

                
    if( header->get_ref_count() != 0 )    //    still have objects reference this
                    return;

                parent 
    = header->parent;

                
    if( header->lchild && header->rchild )    //    has left child and right child
                {
                    node 
    = find_rightmost_child( header->lchild );

                    
    //    rebuild the links
                    if( node != header->lchild )
                    
    {
                        node
    ->parent->rchild = node->lchild;
                        
    if( node->lchild )
                            node
    ->lchild->parent = node->parent;

                        node
    ->lchild = header->lchild;
                        node
    ->lchild->parent = node;
                    }


                    node
    ->rchild = header->rchild;
                    node
    ->rchild->parent = node;
                    node
    ->parent = parent;

                    
    if( parent )    //    has parent
                    {
                        
    if( parent->lchild == header )
                            parent
    ->lchild = node;
                        
    else if( parent->rchild == header )
                            parent
    ->rchild = node;
                    }

                    
    else    //    it's the root
                    {
                        aligned_queue 
    = node;
                    }

                }

                
    else if( header->lchild )    //    has only left child
                {
                    
    //    rebuild the links
                    node = header->lchild;
                    node
    ->parent = parent;

                    
    if( parent )    //    has parent
                    {
                        
    if( parent->lchild == header )
                            parent
    ->lchild = node;
                        
    else if( parent->rchild == header )
                            parent
    ->rchild = node;
                    }

                    
    else    //    it's the root
                    {
                        aligned_queue 
    = node;
                    }

                }

                
    else if( header->rchild )    //    has only right child
                {
                    
    //    rebuild the links
                    node = header->rchild;
                    node
    ->parent = parent;

                    
    if( parent )    //    has parent
                    {
                        
    if( parent->lchild == header )
                            parent
    ->lchild = node;
                        
    else if( parent->rchild == header )
                            parent
    ->rchild = node;
                    }

                    
    else    //    it's the root
                    {
                        aligned_queue 
    = node;
                    }

                }

                
    else    //    has no child
                {
                    
    if( parent )    //    has parent
                    {
                        
    if( parent->lchild == header )
                            parent
    ->lchild = NULL;
                        
    else if( parent->rchild == header )
                            parent
    ->rchild = NULL;
                    }

                    
    else    //    it's the root, clear it
                    {
                        aligned_queue 
    = NULL;
                    }

                }


                allocated_size 
    -= ( sizeof(MemoryHeader) + size );
                available_size 
    += ( sizeof(MemoryHeader) + size );

                sys_aligned_dealloc( header );    
    //    deallocate the block
            }

        }


    private:
        
    //    help functions

        FORCEINLINE 
    void    dealloc_header( MemoryHeader *node )
        
    {
            
    if( node )
            
    {
                
    if( node->lchild )
                    dealloc_header( node
    ->lchild );

                
    if( node->rchild )
                    dealloc_header( node
    ->rchild );

                sys_dealloc( node );
            }

        }


        FORCEINLINE 
    void    dealloc_aligned_header( MemoryHeader *node )
        
    {
            
    if( node )
            
    {
                
    if( node->lchild )
                    dealloc_aligned_header( node
    ->lchild );

                
    if( node->rchild )
                    dealloc_aligned_header( node
    ->rchild );

                sys_aligned_dealloc( node );
            }

        }


        FORCEINLINE MemoryHeader    
    *find_rightmost_child( MemoryHeader *node )
        
    {
            
    while( node && node->rchild )
            
    {
                node 
    = node->rchild;
            }


            
    return node;
        }


        FORCEINLINE MemoryHeader    
    *get_memory_header( void *ptr )
        
    {
            
    //    get the biased value first
            MemoryHeaderBias    *pb = (MemoryHeaderBias *)((char *) ptr - sizeof(MemoryHeaderBias));

            
    //    then get the header using the biased value
            MemoryHeader    *header = (MemoryHeader *)((char *) ptr - (*pb));

            
    return header;
        }


    private:
        
    //    encapsulate system operations

        FORCEINLINE 
    void    *sys_alloc( UINT size )
        
    {
            
    return malloc( size );
        }


        FORCEINLINE 
    void    *sys_aligned_alloc( UINT size, UINT align )
        
    {
            
    return _mm_malloc( size, align );
        }


        FORCEINLINE 
    void    sys_dealloc( void *ptr )
        
    {
            free( ptr );
        }


        FORCEINLINE 
    void    sys_aligned_dealloc( void *ptr )
        
    {
            _mm_free( ptr );
        }


    private:
        
    //    memory statistics
        UINT                        allocated_size, 
                                    available_size;

        
    //    implement priority queues to record all the allocations
        MemoryHeader                *queue;
        MemoryHeader                
    *aligned_queue;
    }
    ;


    #pragma pack(pop)



    #endif    //    __MEM_MAN__



  • 相关阅读:
    第三次作业
    第二次作业
    第一次作业
    实验二
    第一次试验
    第五次作业
    第四次作业
    第三次作业
    第二次作业
    第一次作业
  • 原文地址:https://www.cnblogs.com/len3d/p/936403.html
Copyright © 2011-2022 走看看