内存池(2)

内存池(2)

/*
* 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
/******************************************************************************/
/******************************************************************************/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值