snifer

【原创】基于嵌入式系统的kmalloc解密

0
阅读(1823)

kmalloc很像一个最能干的管家。

kmalloc内存分配函数和应用层的malloc函数很相似,只是这个函数运行得很快-一除非它被阻塞。它不清零它获得的内存空间,分配给它的区域仍存放着原有的数据。kmalloc函数在<linux/slab.h>中定义,实际上,它是通过下一层的__kmalloc完成内存分配的。

static void *kmalloc(size_t size, int flags)
void * __kmalloc (size_t size, int flags)

kmalloc函数的第一个参数是size(大小),第二个参数,flags是优先权参数,它会使kmalloc函数在寻找空闲页较困难时改变函数的行为。最常用的优先权是GFP_KERNEL,它的意思是该内存分配(内部是通过调用get_free_pages来实现的,所以名字中带GFP是由运行在内核态的进程调用的。也就是说,调用它的函数属于某个进程的,使用GFP_KERNEL优先权允许kmalloc函数在系统空闲内存低于水平线min_free_pages时延迟分配函数的返回。当空闲内存太少时,kmalloc函数会使当前进程进入睡眠,等待空闲页的出现。

新的页面可以通过以下几种途径获得。一种方法是换出其他页:因为对换需要时间,进程会等待它完成,这时内核可以调度执行其他的任务。因此,每个调用kmalloc(GFP_KERNEL)的内核函数都应该是可重入的。

系统物理内存的管理是由内核负责的,物理内存只能按页大小进行分配。这就需要一个面向页的分配技术以取得计算机内存管理上最大的灵活性。类似malloc函数的简单的线性的分配技术不再有效了。在象Linux内核这样的面向页的系统中内存如果使用线性分配的策略就很难维护。空洞的处理很快就会成为一个问题,会导致内存浪费,降低系统的性能。

Linux是通过维护页面池来处理kmalloc的分配要求的,这样页面就可以很容易地放进或者取出页面池。为了能够满足超过PAGE_SIZE字节数大小的内存分配请求,mm/slab.c文件维护页面簇的列表。每个页面簇都存放着连续若干页,可用于DMA分配。Linux所使用的分配策略的最终方案是,内核只能分配一些预定义的固定大小的字节数组。如果申请任意大小的内存空间,那么很可能系统会多给你一点。

这些预定义的内存大小一般“稍小于2的某次方”(而在更新的实现中系统管理的内存大小恰好为2的各次方)。如果能记住这一点,就可以更有效地使用内存。例如,需要一个2000字节左右的缓冲区,最好还是申请2000字节,而不要申请2048字节。申请恰好是2的幂次的内存空间是最糟糕的情况了-内核会分配两倍于申请空间大小的内存。 

暑假很长,就讲这么多吧。