Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15497399
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: C/C++

2007-10-11 14:14:39

浅析MiniGUI v1.62小内存自管理函数所在文件Fixstr.c

文章来源:http://gliethttp.cublog.cn

MiniGUI对内存的使用遵循如下法则:
1.malloc用在只有1次性分配,或者释放和分配频率不高,或者超出小内存管理大小,或者相应小内存没有了的情况下
2.当释放和分配频率很高时,MiniGUI使用FixStrAlloc()和FreeFixStr()两个加速函数自己管理小块内存
  的分配和释放,但是MiniGUI的小内存管理代码有些地方似乎效率可以提高,
  比如*bitmap |= (0x80 >> (stroff%8));就没有必要使用余取运算,因为%运算要使用到/除法运算,
  很耗时,因此直接stroff&0x7就可以;另一个地方就是[0]数组位置存放的是大数据,致使每次长度和索引
  关联计算时,总是需要进行一次翻转运算(当然可以使用static数组,直接读取value[i]中length值)
  bufflen = 1 << (NR_HEAP + 1 - i),所以应该在初始化时,做一些运算,[0]对应低数值,这样避开
  翻转,最后直接bufflen = 1 << i就搞定,总之,感觉minigui在内存管理速度方面仍需要做改进;
  另外MiniGUI的所管理的小块内存区域不能动态生长和释放,只能是根据系统设计之处的最大值,
  固化之前指定好,所以对于控件动态增量不固定的应用系统,可能随着系统运行时间的增长,因为控件的不断增加,
  而不能在heap区域找到空闲的数组,进而使用malloc申请的那些控件的速度开始下降,当然这样的应用系统,
  目前为止我还没有见到过,因为系统动态性都很小,所以一般我会把内存指定足够大来由GUI系统管理,
  不过确实存在这样一种局限性.
//-----------------------------------------------------------
以下为Fixstr.c文件源程序:
static struct FIXSTR {
    BYTE bitmap[LEN_BITMAP];
    int offset[NR_HEAP];
    char* heap[NR_HEAP + 1];
#ifndef _LITE_VERSION
    pthread_mutex_t lock;
#endif
} FixStrHeap;

BOOL InitFixStr (void)
{
    int i, j, offset;
    BYTE* bitmap;
    //2007-10-11 gliethttp
    //首先申请一块足够大的用来自管理小内存的连续内存区
    //之所以乘8是因为,FixStrAlloc()函数中for(j = 0; j < 8; j++)运算
    //这样FixStrAlloc()可以直接对常量---8进行运算,不用担心bits&0x07是否还有数据
    //进而提高运算速度
    if (!(FixStrHeap.heap [0] = malloc (MAX_LEN_FIXSTR * 8 * NR_HEAP))) return FALSE;

    for (i = 1; i <= NR_HEAP; i++) {
        FixStrHeap.heap[i] = FixStrHeap.heap[0] + MAX_LEN_FIXSTR * 8 * i;
    }
    //heap[NR_HEAP]为自管理连续内存区的结尾地址,也就是free区域有效开始地址
    bitmap = FixStrHeap.bitmap;
    offset = 0;
    for (i = 0; i < NR_HEAP; i++) {
        for (j = 0; j < (1<<i); j ++)
            bitmap[j] |= 0xFF;
        //2007-10-11 gliethttp
        //bitmap[0]管理  1个8位组---每个位组2k ---共16k
        //bitmap[1]管理  2个8位组---每个位组1k ---共16k
        //bitmap[2]管理  4个8位组---每个位组512---共16k
        //bitmap[3]管理  8个8位组---每个位组256---共16k
        //bitmap[4]管理 16个8位组---每个位组128---共16k
        //bitmap[5]管理 32个8位组---每个位组64 ---共16k
        //bitmap[6]管理 64个8位组---每个位组32 ---共16k
        //bitmap[7]管理128个8位组---每个位组16 ---共16k
        //bitmap[8]管理256个8位组---每个位组8  ---共16k
        //bitmap[9]管理512个8位组---每个位组4  ---共16k
        //bitmap总大小为1+2+4+8+16+32+64+128+256+512个字节
        bitmap += 1<<i;
        //2007-10-11 gliethttp
        //offset和bitmap是绑定在一起使用的
        //即:bitmap+offset[i]开始的map是管理heap[i]这组内存块的
        FixStrHeap.offset[i] = offset;
        offset += 1<<i;
    }
    
#ifndef _LITE_VERSION
    //对于非lite的threads配置等,需要锁机制来保护内存申请部分
    //如果系统对优先级翻转并不关心,可以直接使用semaphore作为锁
    //因为mutex的效率多少都要比semaphore机制低
    pthread_mutex_init (&FixStrHeap.lock, NULL);
#endif
    return TRUE;
}

void TerminateFixStr (void)
{
#ifndef _LITE_VERSION
    pthread_mutex_destroy (&FixStrHeap.lock);
#endif
    //minigui退出,调用free释放由malloc申请的大块管理内存
    free (FixStrHeap.heap[0]);
}
static char zero_string [] = {'\0'};

char* GUIAPI FixStrAlloc (int len)
{
    UINT ulen = (UINT)len;
    int i, j, btlen, bufflen;
    char* heap;
    BYTE* bitmap;

    if (len < 0)
        return NULL;
        
    if (len == 0)
        return zero_string;//仅对<0数据为非法申请,长度0由zero_string对应
   
    if (len >= MAX_LEN_FIXSTR)
    //超过常用小数据块的大小,那么malloc重新申请
    //使用malloc比较耗时一些
        return (char*)malloc (len + 1);
    i = 0;
    while (ulen) {
        ulen = ulen >> 1;
        //求取2的幂数值
        i++;
    }
    //2007-10-11 gliethttp
    //bitmap[0]管理  1个8位组---每个位组2k ---共16k
    //bitmap[1]管理  2个8位组---每个位组1k ---共16k
    //bitmap[2]管理  4个8位组---每个位组512---共16k
    //bitmap[3]管理  8个8位组---每个位组256---共16k
    //bitmap[4]管理 16个8位组---每个位组128---共16k
    //bitmap[5]管理 32个8位组---每个位组64 ---共16k
    //bitmap[6]管理 64个8位组---每个位组32 ---共16k
    //bitmap[7]管理128个8位组---每个位组16 ---共16k
    //bitmap[8]管理256个8位组---每个位组8  ---共16k
    //bitmap[9]管理512个8位组---每个位组4  ---共16k
    //bitmap总大小为1+2+4+8+16+32+64+128+256+512个字节
    //2007-10-11 gliethttp
    //i=2,保证4字节对齐
    if (i == 1) i = 2;
    bufflen = 1 << i;
    //#define MAX_LEN_FIXSTR 2048
    //#define NR_HEAP 10
    //#define LEN_BITMAP (1+2+4+8+16+32+64+128+256+512)
    i = NR_HEAP + 1 - i;
    //2007-10-11 gliethttp
    //重新计算后的i就是下面的heap索引值
    //heap[0]管理  8个 2k内存块
    //heap[1]管理 16个 1k内存块
    //heap[2]管理 32个512内存块
    //heap[3]管理 64个256内存块
    //heap[4]管理128个128内存块
    //heap[5]管理256个 64内存块
    //heap[6]管理512个 32内存块
    //heap[7]管理 1k个 16内存块
    //heap[8]管理 2k个  8内存块
    //heap[9]管理 4k个  4内存块
#ifndef _LITE_VERSION
    //操作内存管理全局量,申请持有全局量修改权的锁
    pthread_mutex_lock (&FixStrHeap.lock);
#endif
    heap = FixStrHeap.heap[i];
    bitmap = FixStrHeap.bitmap + FixStrHeap.offset[i];
    btlen = 1 << i;
    //btlen为8位组个数
    for (i = 0; i < btlen; i++) {
    //2007-10-11 gliethttp
    //数据块的个数肯定是8的倍数,这在InitFixStr()中已经故意申请成8的倍数了
    //为了提高效率可以,加入一个判断,即:
    //if(*bitmap != 0xff)这样再执行for(j = 0; j < 8; j++)
    //这在系统运行一段时间之后能够很好提高效率,进而让高效不随时间的增加而降低
        for(j = 0; j < 8; j++) {
            if (*bitmap & (0x80 >> j)) {
                *bitmap &= (~(0x80 >> j));
#ifndef _LITE_VERSION
                pthread_mutex_unlock (&FixStrHeap.lock);
#endif
#if 0
                printf ("FixStrAlloc, len: %d, heap: %p.\n", len, heap);
#endif
                return heap;//我们找到了一个4,8...字节的小数据区
            }
            //heap执行8位组中的第0~7个组的下一个组
            //我觉得可以直接在return heap;之前加入一句:heap += j*bufflen;
            //然后在下面bitmap++的前面加上,heap += 8*bufflen;这样效率会高一些,
            //尤其当运行一段时间heap使用了一部分之后,效率提高的比较明显
            heap += bufflen;
        }
        //指向下1个8位组对应的bitmap
        bitmap++;
    }

#ifndef _LITE_VERSION
    pthread_mutex_unlock (&FixStrHeap.lock);//释放持有权

#endif
    //管理的相应小内存块已经全部用完,只能使用malloc
    //如:heap[3]管理 64个256内存块可能全部耗尽,但是heap[0]的2k内存块
    //可能1块都没有用呢,但是minigui不管,还是使用下面的malloc申请
    //这也突显了minigui的小内存管理单元的局限性,它仅仅在一定程度上提高了部分
    //控件的内存申请、释放效率
    return (char*)malloc (len + 1);
}

void GUIAPI FreeFixStr (char* str)
{
    char* heap;
    BYTE* bitmap;
    int i;
    int bufflen;
    int stroff;
    
    if (str [0] == '\0')
        return;
        
    if (str >= FixStrHeap.heap [NR_HEAP] || str < FixStrHeap.heap [0]) {
        //释放的内存区域不是由FixStrAlloc管理的,而是由free管理
        free (str);
        return;
    }
    
    for (i = 1; i <= NR_HEAP; i++) {
        if (str < FixStrHeap.heap[i])
        //str在当前heap的前一个heap中
            break;
    }
    i--;
    
    bufflen = 1 << (NR_HEAP + 1 - i);

#ifndef _LITE_VERSION
    pthread_mutex_lock (&FixStrHeap.lock);
#endif
    //重新计算后的i就是下面的heap索引值
    //heap[0]管理  8个 2k内存块
    //heap[1]管理 16个 1k内存块
    //heap[2]管理 32个512内存块
    //heap[3]管理 64个256内存块
    //heap[4]管理128个128内存块
    //heap[5]管理256个 64内存块
    //heap[6]管理512个 32内存块
    //heap[7]管理 1k个 16内存块
    //heap[8]管理 2k个  8内存块
    //heap[9]管理 4k个  4内存块
    heap = FixStrHeap.heap[i];
    bitmap = FixStrHeap.bitmap + FixStrHeap.offset[i];

    stroff = 0;
    //2007-10-11 gliethttp
    //这里minigui是很肯定的假设str一定能够在
    //该heap中有以相应字节数目为对齐值的项,如果没有那可就惨了,可能就此down机了
    //当然加入过多判断,难免会增加内存申请释放的时间花费
    //这也是假设完全安全的一个让人信服的,无话可说的理由之一
    while (str != heap) {
        heap += bufflen;
        stroff ++;
    }
#if 0
    printf ("FreeFixStr, len: %d, str: %p: heap: %p.\n", strlen (str), str, heap);
#endif
    //该str位于本heap的第stroff个bufflen字节内存块
    bitmap = bitmap + (stroff>>3);
    *bitmap |= (0x80 >> (stroff%8));//可以使用stroff&0x07替换stroff%8进而提高效率,毕竟余取运算涉及到除法
#ifndef _LITE_VERSION
    pthread_mutex_unlock (&FixStrHeap.lock);
#endif
}
  总之,MiniGUI v1.62的小内存自管理机制,确实有很大的局限性,当然它也确实在小范围内,提高了MiniGUI的效率.

阅读(3157) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~