genalloc — 通用内存分配器

发布时间:2016-12-7 18:36:36 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"genalloc — 通用内存分配器",主要涉及到genalloc — 通用内存分配器方面的内容,对于genalloc — 通用内存分配器感兴趣的同学可以参考一下。

From: http://www.2cto.com/kf/201302/187782.html genalloc 是 linux 内核提供的通用内存分配器,源码位于 lib/genalloc.c。这个分配器为独立于内核以外的内存块提供分配方法,采用的是最先适配原则,android 最新的 ION 内存管理器对 ION_HEAP_TYPE_CARVEOUT 类型的内存就是采用的这个分配器。 1、基础数据结构 首先看下分配器用到的几个数据结构,struct gen_pool 用来描述一个内存池: [cpp]   struct gen_pool {       rwlock_t lock;             /* 链表读写锁 */       struct list_head chunks;   /* 内存池中内存块的链表 */       int min_alloc_order;       /* 内存池最小分配单元的阶数,大小为 2^min_alloc_order */   };   在使用的时候需要向内存池中加入内存块,一个内存块即一大块连续的物理内存,用 struct gen_pool_chunk 来描述: [cpp]   struct gen_pool_chunk {       spinlock_t lock;              /* 操作内存块时用到的自旋锁 */       struct list_head next_chunk;  /* 加入内存池的节点 */       unsigned long start_addr;     /* 内存块的起始地址 */       unsigned long end_addr;       /* 内存块的结束地址 */       unsigned long bits[0];        /* 内存块的位图 */   };   2、函数接口及调用方法 genalloc 用到的函数接口有下面几个: [cpp]   /* 创建一个内存池,主要工作是完成 struct gen_pool 的初始化 */   struct gen_pool *gen_pool_create(int min_alloc_order, int nid);   /* 向内存池中加入内存块,addr 为起始地址,size 为大小 */   int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, int nid);   /* 销毁一个内存池 */   void gen_pool_destroy(struct gen_pool *pool);   /* 内存池分配内存的函数 */   unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size);   /* 内存池释放内存的函数 */   void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size);   对通用内存分配器的一般使用方法如下: [cpp]   /* 初始化内存池,需要创建以及加入内存块,参数为:起始地址、大小、最小分配阶数 */   static void *mm_init(uint32_t addr, uint32_t size, uint32_t order)   {       struct gen_pool *pool;          pool = gen_pool_create(order, 0);       if (pool == NULL) {           return NULL;       }          if (gen_pool_add(pool, addr, size, 0) != 0) {           gen_pool_destroy(pool);              return NULL;       }          return pool;   }      /* 销毁内存池 */   static void mm_exit(void *handle)   {       gen_pool_destroy(handle);   }      /* 分配函数 */   static uint32_t mm_alloc(void *handle, uint32_t size)   {       return gen_pool_alloc(handle, size);   }      /* 释放函数 */   static void mm_free(void *handle, uint32_t addr, uint32_t size)   {       return gen_pool_free(handle, addr, size);   }      /* 提供给上一级内存管理器调用 */   struct xxx_mem_ops mm_ops = {       .init = mm_init,       .exit = mm_exit,       .alloc = mm_alloc,       .free = mm_free,   };   3、分配函数解析 genalloc 通过 gen_pool_alloc 函数来分配内存,下面我们分析一下这个函数的代码: [cpp]   unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)   {       struct list_head *_chunk;       struct gen_pool_chunk *chunk;       unsigned long addr, flags;       int order = pool->min_alloc_order;       int nbits, bit, start_bit, end_bit;          if (size == 0)           return 0;          nbits = (size + (1UL << order) - 1) >> order;  /* 计算申请的内存需要几个连续的最小单元 */          read_lock(&pool->lock);       list_for_each(_chunk, &pool->chunks) {         /* 遍历内存池 */           chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);              end_bit = (chunk->end_addr - chunk->start_addr) >> order;        /* 计算当前内存池长度 */           end_bit -= nbits + 1;              spin_lock_irqsave(&chunk->lock, flags);           bit = -1;           while (bit + 1 < end_bit) {  /* 循环查找最先适配的内存区 */               bit = find_next_zero_bit(chunk->bits, end_bit, bit + 1);     /* 寻找为0的bit */               if (bit >= end_bit)      /* 循环结束 */                   break;                  start_bit = bit;         /* 起始位置 */               if (nbits > 1) {         /* 如果申请的内存大于一个最小单元,查找连续的nbits个单元 */                   bit = find_next_bit(chunk->bits, bit + nbits,bit + 1);                   if (bit - start_bit < nbits)                       continue;               }                  addr = chunk->start_addr + ((unsigned long)start_bit << order);  /* 计算申请的内存的起始地址 */               while (nbits--)                   __set_bit(start_bit++, chunk->bits);  /* 将申请到的单元全部标记为已用 */               spin_unlock_irqrestore(&chunk->lock, flags);               read_unlock(&pool->lock);               return addr;           }           spin_unlock_irqrestore(&chunk->lock, flags);       }       read_unlock(&pool->lock);       return 0;   }   因为是用的最先适配原则,所以逻辑比较简单,我们也可以根据自己的需求实现最适合分配器以及伙伴分配器。

上一篇:WorkLight 5 studio内置服务器的端口问题
下一篇:android wifi ralink rt3070开发记录

相关文章

相关评论