Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1945583
  • 博文数量: 383
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 4061
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-24 18:53
文章分类

全部博文(383)

文章存档

2011年(1)

2010年(9)

2009年(276)

2008年(97)

我的朋友

分类: LINUX

2009-03-21 15:39:20

调试平台:VS2005
参考文章:内存管理内幕

 

/*********************************************************************************************
模块功能:ipanel内存分配释放。由于ipanel分配内存块较大,当操作系统内存碎片过多,且没有及时清理
         的情况下,容易出现分配失败的情况,这时需要事先独立分配一块内存,提供给ipanel自身管理
模块描述:加入内存块头信息,存放分配内存块的大小、上下已用内存块头信息节点位置,采用链表管理
分配优先:检查memBaseAddr是否为第一节点(first),否,则尝试在memBaseAddr进行分配 ->
         遍历链表,检查两已用内存块之间是否有可用空间,如有并大于等于分配大小,则进行分配 ->
         在链表最后节点之后的剩余空间进行分配
改进权衡:

         1、采用独立的空间存放内存块头信息
         2、遍历所有已用内存块头信息链表,找到两已用内存块之间的可用空间最接近于要分配内存的大
            小,并在该处进行分配,这样ipanel自身内存管理的碎片更少,但所耗的时间更长
         3、直接在链表最后节点之后的剩余空间进行分配,当模块分配释放模式为malloc->malloc->
            malloc->malloc->...->free->free->free->free时,推荐采用这种分配模式
*********************************************************************************************/

#include "stdafx.h"
#include <stdio.h>
#include <malloc.h>

void *memBaseAddr = NULL;//可分配内存的首地址
unsigned int totalMemSize = 0;//可分配内存的总大小

struct mem_block_info {
    unsigned int size;//等于实际分配内存大小加上结构体mem_block_info的大小
    struct mem_block_info *preview;//存放上已用内存块的头信息节点位置
    struct mem_block_info *next;//存放下已用内存块的头信息节点位置
};
struct mem_block_info *first = NULL;
//链表头节点

/*初始化可分配内存的base address和memory size*/
void my_set_mem_base_addr(void *addr, int size)
{
    memBaseAddr = addr;
    totalMemSize = size;
}

/*释放已用内存,删除内存块头信息节点*/
void free_used_mem(struct mem_block_info *used)
{
    if (used == first)
        first = first->next;
    else
        used->preview->next = used->next;
}

/*遍历链表,寻找可用空间。返回已分配空间头信息节点*/
struct mem_block_info *search_available_mem(unsigned int size /*[in]: 要求分配空间大小*/)
{
    unsigned int freeSize;
    struct mem_block_info *result = NULL;
    struct mem_block_info *current = first;
    if (size % 4)
        size = (size/4 + 1) * 4;
//强制四字节对齐

    if (!first)
    {
        //当内存是第一次分配时
        freeSize = totalMemSize;
        if (size + sizeof(struct mem_block_info) > freeSize)
        {
            result = NULL;
            return result;
        }
        else
        {
            result = (struct mem_block_info *)memBaseAddr;
            result->preview = NULL;
            result->next = NULL;
            result->size = size + sizeof(struct mem_block_info);
            first = result;
            return result;
        }    
    }
    if (memBaseAddr != first)
    {
        //检查第一个节点是否从memBaseAddr开始,如果否,优先从memBaseAddr进行分配
        freeSize = (unsigned int)first - (unsigned int)memBaseAddr;
        if (size + sizeof(struct mem_block_info) <= freeSize)
        {
            result = (struct mem_block_info *)memBaseAddr;
            result->preview = NULL;
            result->next = first;
            result->size = size + sizeof(struct mem_block_info);
            first = result;
            return result;
        }
    }
    while (current)
    {
        if (current->next == NULL)
        {
            //优先从两内存块节点之间的剩余空间分配,如果都没有足够空间,则从后面的剩余内存进行分配
            freeSize = totalMemSize - ((unsigned int)current - (unsigned int)memBaseAddr + current->size);
            if (size + sizeof(struct mem_block_info) > freeSize)
            {
                result = NULL;
                return result;
            }
            else
            {
                result = (struct mem_block_info *)((unsigned int)current + current->size);
                result->preview = current;
                result->next = NULL;
                result->size = size + sizeof(struct mem_block_info);
                current->next = result;
                return result;
            }
        }
        else
        {
            //检查两块已分配的内存块之间是否有足够的空间,如果有,则分配
            freeSize = (unsigned int)(current->next) - (unsigned int)current - current->size;
            if (size + sizeof(struct mem_block_info) <= freeSize)
            {
                result = (struct mem_block_info *)((unsigned int)current + current->size);
                result->size = size + sizeof(struct mem_block_info);
                result->preview = current;
                result->next = current->next;
                current->next = result;
                return result;
            }
        }
        //否,则继续遍历
        current = current->next;
    }
    return result;
}

void *my_malloc(int memsize)
{
    struct mem_block_info *result = NULL;
    result = search_available_mem(memsize);
    if (!result)
        return NULL;
    return (void *)((unsigned int)result + sizeof(struct mem_block_info));
}

void my_free(void* memptr)
{
    struct mem_block_info *used;
    if (memptr)
    {
        used = (struct mem_block_info *)((unsigned int)memptr - sizeof(struct mem_block_info));
        free_used_mem(used);
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    //测试程序
    printf("struct mem_block_info size %d\n", sizeof(struct mem_block_info));
    struct mem_block_info *rc;
    void *ptr = NULL;
    void *first = NULL;
    void *second = NULL;
    void *third = NULL;
    void *fourth = NULL;
    void *fineth = NULL;
    unsigned int totalmem = 0xa00000;
    ptr = (void *)malloc(totalmem);
    my_set_mem_base_addr(ptr, totalmem);
    first = my_malloc(0x10000);
    second = my_malloc(0x20000);
    third = my_malloc(0x40);
    my_free(second);
    fourth = my_malloc(0x800);
    my_free(first);
    fineth = my_malloc(0x40000);
    *(unsigned int *)fineth = 0x40;
    printf("*fineth 0x%x\n", *(unsigned int *)fineth);
    rc = (struct mem_block_info *)((unsigned int)fourth - sizeof(struct mem_block_info));
    printf("fineth struct info: size 0x%x, next %p", rc->size, rc->next);
    return 0;
}

 
PS:
近日又研究了一下Unix下的内存分配策略,才晓得常见的策略有:
first-fit、next-fit、best-fit、quick-fit
quick-fit速度快,但空间浪费大,明显不适合我们模块这种情形
best-fit内存碎片少,但时间消耗大,在内存紧张的情形下可用
first-fit是我如今采用的一个策略
next-fit我感觉比first-fit有很大的改进,特别适用于内存会被多次分配释放的情形
 
   如果今后要进行改进的话,可以考虑将next-fit和best-fit结合
阅读(851) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~