内存池算法---实现文件

来源:互联网 发布:查询淘宝小号信誉 编辑:程序博客网 时间:2024/05/18 17:02

/*

 * The young Library

 * Copyright (c) 2005 by Yang Huan(杨桓)

 

 * Permission to use, copy, modify, distribute and sell this software for any

 * purpose is hereby granted without fee, provided that the above copyright

 * notice appear in all copies and that both that copyright notice and this

 * permission notice appear in supporting documentation.

 * The author make no representations about the suitability of this software

 * for any purpose. It is provided "as is" without express or implied warranty.

 */

 

/*

 * 内存池由 MEMORY_POOL_LISTS 个链表组成,每个链表分别管理不同大小的内存块,

 * 每个链表管理的内存块大小 = MEMORY_POOL_MIN + 索引 * MEMORY_POOL_ALIGN

 *

 * 内存池原理图:

 * 索引:0      1     2     3           ......         MEMORY_POOL_LISTS - 1

 * --------------------------------------------------------------------------

 * | useable |     |     |     |        ......        |                     |

 * --------------------------------------------------------------------------

 * |  buffer |

 * -----------

 * |  first  |

 * -----------

 *      |

 *      |

 *      |   --------

 *      ->| next |--

 *          |------|   |

 *          | use  |   |

 *          |------|   |

 *          | page |   |

 *          --------   |

 *                     |

 *  ----------

 *  |

 *  |   --------

 *  ->| next | --> NULL

 *      |------|

 *      | use  | 注:使用该字的二进制位来记录内存页中各内存块的使用状态

 *      |------|

 *      | page | 注:内存页大小 = 该链表处理的内存块大小 * use的位数

 *      --------

 */

 

/******************************************************************************/

/******************************************************************************/

#include <stdio.h>

#include <stdlib.h>

#include "yc_memory.h"

 

#ifdef __cplusplus

    namespace youngc {  extern "C" {

#endif

/******************************************************************************/

/******************************************************************************/

 

enum YOUNG_LIBRARY_MEMORY_CONSTANT

{

    MEMORY_ALIGN_SIZE = sizeof(int),

    MEMORY_POOL_BUFFER = 8,

    MEMORY_POOL_ALIGN = 4,

    MEMORY_POOL_MIN = 8,

    MEMORY_POOL_MAX = 128,

    MEMORY_POOL_BLOCKS = sizeof(ylib_word_t) * BYTE_BITS,

    MEMORY_POOL_LISTS = ( MEMORY_POOL_MAX - MEMORY_POOL_MIN )

                        / MEMORY_POOL_ALIGN + 1

};

 

typedef struct memory_page

{

    ylib_word_t          use;  /* 二进制位映射的内存块已使用则该位为1,否则为0 */

    struct memory_page*  next; /* 下一个内存页 */

} mempage_t;

 

typedef struct memory_list

{

    size_t      useable;                    /* 未满的可供分配的内存页数 */

    mempage_t*  buffer[MEMORY_POOL_BUFFER]; /* 页面缓存 */

    mempage_t*  first;                      /* 第一个内存页 */

} memlist_t;

 

#define  MEMALLOC( bytes)  malloc( bytes )

 

#define  MEMFREE( ptr )    free( ptr )

 

#define  LIST_INDEX( bytes ) /

         ( (bytes) <= MEMORY_POOL_MIN ? 0 /

           : ((bytes) - MEMORY_POOL_MIN + MEMORY_POOL_ALIGN - 1) /

             / MEMORY_POOL_ALIGN )

 

#define  BLOCK_SIZE( index )  ( MEMORY_POOL_MIN + (index) * MEMORY_POOL_ALIGN )

 

#define  PAGE_SIZE( index )  ( BLOCK_SIZE(index) * MEMORY_POOL_BLOCKS )

 

/******************************************************************************/

/******************************************************************************/

 

static void (*pool_lock)( size_t ) = NULL;

static void (*pool_unlock)( size_t ) = NULL;

static size_t pool_alloc_count = 0;

static size_t pool_dealloc_count = 0;

static memlist_t pool[MEMORY_POOL_LISTS] = { {0, {NULL}, NULL} };

 

static unsigned char bitmap[] =

{

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,

    0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0

};

 

/******************************************************************************/

/******************************************************************************/

 

size_t get_pool_lists_count( void )

{

    return MEMORY_POOL_LISTS;

}

 

size_t get_pool_alloc_count( void )

{

    return pool_alloc_count;

}

 

size_t get_pool_dealloc_count( void )

{

    return pool_dealloc_count;

}

 

void set_pool_lock( void (*lock)(size_t) )

{

    pool_lock = lock;

}

 

void set_pool_unlock( void (*unlock)(size_t) )

{

    pool_unlock = unlock;

}

 

/******************************************************************************/

 

size_t memalign( size_t element_size, bool memory_type )

{

    size_t residue = MEMORY_ALIGN_SIZE - 1;

    size_t alignsize = element_size & ~residue;

 

    if( element_size & residue )

        alignsize += MEMORY_ALIGN_SIZE;

 

    if( memory_type == true && alignsize < sizeof(ylib_inner_t) )

        alignsize = sizeof(ylib_inner_t);

 

    return alignsize;

}

 

/******************************************************************************/

 

void pool_print( void )

{

    int i, j;

    mempage_t* curr;

    ylib_word_t mask;

    char *str_last, bits[MEMORY_POOL_BLOCKS + 1] = { '/0' };

 

    for( i = 0; i < MEMORY_POOL_LISTS; ++i )

    {

        if( !(pool[i].first) )

            continue;

 

        printf( "/npool[%d] chunk = %d", i, BLOCK_SIZE(i) );

        printf( "/n/tpool[%d].useable = %u", i, pool[i].useable );

        for( j = 0; j < MEMORY_POOL_BUFFER; ++j )

            printf( "/n/tpool[%d].buffer[%d] = %p", i, j, pool[i].buffer[j] );

        printf( "/n/tpool[%d].first = %p: ", i, pool[i].first );

 

        curr = pool[i].first;

 

        while( curr )

        {

            mask = 1;

            str_last = bits + MEMORY_POOL_BLOCKS;

            for( j = 0; j < MEMORY_POOL_BLOCKS; ++j, mask <<= 1 )

                *--str_last = (char)(curr->use & mask ? '1' : '0');

            printf( "/n/t" );

            printf( "next = %p | use = %s", curr->next, bits );

            curr = curr->next;

        }

    }

}

 

/******************************************************************************/

 

static void* page_alloc( size_t index, mempage_t* curr )

{

    void* ptr = NULL;

    size_t i;

 

    /* 先找到第一个空闲块所在的字节 */

    for( i = 0; i < sizeof(ylib_word_t); ++i )

    {

        ylib_byte_t value = (ylib_byte_t)( curr->use >> (BYTE_BITS * i) );

 

        if( value != YLIB_BYTE_MAX )

        {

            ylib_word_t mask = 1;

            size_t biti = bitmap[value]; /* 从映射表中查找第一个等于 0 的位 */

            mask <<= ( BYTE_BITS * i + biti ); /* 计算掩码 */

            curr->use |= mask; /* 设置使用标志 */

            ptr = (ylib_byte_t*)curr + sizeof(mempage_t)

                  + (i * BYTE_BITS + biti) * BLOCK_SIZE( index );

            if( curr->use == YLIB_WORD_MAX )

                --( pool[index].useable );

            return ptr;

        } /* end if */

    } /* end for i */

 

    return ptr;

}

 

/******************************************************************************/

 

void* pool_alloc( size_t bytes )

{

    void* ptr = NULL;

 

    if( bytes > MEMORY_POOL_MAX )

    {

        ptr = MEMALLOC( bytes );

    }

    else

    {

        int i;

        mempage_t* pg = NULL;

        size_t index = LIST_INDEX( bytes );

 

        if( pool_lock )

            pool_lock( index );

 

        if( pool[index].first && pool[index].useable > 0 )

        {

            mempage_t *prev = NULL, *curr = NULL;

 

            /* 先查找页面缓存 */

            for( i = 0; i < MEMORY_POOL_BUFFER; ++i )

            {

                if( pool[index].buffer[i] )

                {

                    ptr = page_alloc( index, pool[index].buffer[i] );

 

                    /* 如果该页已满,则将该页自页面缓存中退出 */

                    if( pool[index].buffer[i]->use == YLIB_WORD_MAX )

                        pool[index].buffer[i] = NULL;

                    else if( i > 0 )

                    {

                        /* 如果该页不在缓存首,则将该页调整至缓存首 */

                        pool[index].buffer[0] = pool[index].buffer[i];

                        pool[index].buffer[i] = NULL;

                    }

 

                    goto EXIT_POOL_ALLOC;

                }

            } /* 页面缓存 */

 

            /* 页面缓存为空,则遍历链中的所有内存页寻找空闲的内存块 */

            curr = pool[index].first;

            while( curr )

            {

                if( curr->use == YLIB_WORD_MAX ) /* 该页中没有空闲块 */

                {

                    /* 进入下一页 */

                    prev = curr;

                    curr = curr->next;

                }

                else /* 该页中有空闲块 */

                {

                    size_t count = 0;

                    ptr = page_alloc( index, curr );

 

                    /* 继续遍历链表,寻找其他未满的页面,将之放入页面缓存 */

                    while( curr && count < pool[index].useable )

                    {

                        if( curr->use != YLIB_WORD_MAX )

                        {

                            /* 页面缓存还有位置则放入页面缓存 */

                            if( count < MEMORY_POOL_BUFFER )

                                pool[index].buffer[count] = curr;

 

                            ++count;

 

                            /* 如果当前页未满并且不在链首,则将之移至链首 */

                            if( pool[index].first != curr )

                            {

                                prev->next = curr->next;

                                curr->next = pool[index].first;

                                pool[index].first = curr;

                                curr = prev->next;

                                continue;

                            }

                        }

                        prev = curr;

                        curr = curr->next;

                    }

 

                    goto EXIT_POOL_ALLOC;

                } /* end else */

            } /* end while */

        } /* end if */

        else

        {

            /* 该链下未分配内存页或无空闲块,此时需增加新的内存页 */

            pg = (mempage_t*)MEMALLOC( sizeof(mempage_t) + PAGE_SIZE(index) );

            if( pg )

            {

                pg->next = pool[index].first;

                pool[index].first = pg;

                pg->use = 1;

                ptr = (ylib_byte_t*)pg + sizeof(mempage_t);

                ++( pool[index].useable );

                pool[index].buffer[0] = pg;

            }

        }

 

EXIT_POOL_ALLOC:

        if( pool_unlock )

            pool_unlock( index );

    } /* end else */

 

    if( ptr )

        ++pool_alloc_count;

 

    return ptr;

}

 

/******************************************************************************/

 

void pool_dealloc( void* ptr, size_t bytes )

{

    if( !ptr )

        return;

 

    if( bytes <= MEMORY_POOL_MAX )

    {

        size_t index = LIST_INDEX( bytes );

        size_t pagesize = PAGE_SIZE( index );

        mempage_t *prev = NULL, *curr = pool[index].first;

        ylib_byte_t *begin, *end, *blk = (ylib_byte_t*)ptr;

 

        if( pool_lock )

            pool_lock( index );

 

        while( curr )

        {

            begin = (ylib_byte_t*)curr + sizeof(mempage_t);

            end = begin + pagesize;

            if( blk < begin || blk >= end ) /* 判断ptr是否在当前页内 */

            {

                prev = curr;

                curr = curr->next;

            }

            else

            {

                size_t blk_size = BLOCK_SIZE( index );

 

                /* 检查ptr是否正确 */

                if( (blk - begin) % blk_size == 0 )

                {

                    ylib_word_t mask = 1;

                    size_t blk_index = (blk - begin) / blk_size;

                    size_t old = curr->use;

                    mask <<= blk_index;

                    curr->use &= ~mask;

 

                    /* 如果当前页不在链首,则将之移至链首 */

                    if( pool[index].first != curr )

                    {

                        prev->next = curr->next;

                        curr->next = pool[index].first;

                        pool[index].first = curr;

                    }

 

                    /* 如果归还前内存页已满,则将可用页数加一 */

                    if( old == YLIB_WORD_MAX )

                        ++( pool[index].useable );

 

                    ++pool_dealloc_count;

                }

                break;

            } /* end else */

        } /* end while */

 

        if( pool_unlock )

            pool_unlock( index );

 

        return;

    } /* end if */

 

    /* ptr不是由内存池分配 */

    MEMFREE( ptr );

    ++pool_dealloc_count;

}

 

/******************************************************************************/

 

void pool_free( void* ptr, size_t bytes )

{

    if( ptr )

        pool_dealloc( ptr, bytes );

 

    if( bytes <= MEMORY_POOL_MAX )

    {

        int i;

        size_t index = LIST_INDEX( bytes );

        mempage_t *erase = NULL, *prev = NULL, *curr = pool[index].first;

 

        if( pool_lock )

            pool_lock( index );

 

        while( curr )

        {

            if( curr->use != 0 ) /* 判断是否是空闲页 */

            {

                prev = curr;

                curr = curr->next;

            }

            else

            {

                /* 从页面缓存中退出 */

                for( i = 0; i < MEMORY_POOL_BUFFER; ++i )

                {

                    if( pool[index].buffer[i] == curr )

                    {

                        pool[index].buffer[i] = NULL;

                        break;

                    }

                }

 

                if( prev )

                    prev->next = curr->next; /* 空闲页不在链首 */

                else

                    pool[index].first = curr->next; /* 空闲页在链首 */

 

                /* 将空闲页释放 */

                erase = curr;

                curr = curr->next;

                MEMFREE( erase );

                --( pool[index].useable );

            } /* end if */

        } /* end while */

 

        if( pool_unlock )

            pool_unlock( index );

    }

}

 

/******************************************************************************/

/******************************************************************************/

#ifdef __cplusplus

    }  }

#endif

/******************************************************************************/

/******************************************************************************/

原创粉丝点击