日期:2014-05-16  浏览次数:20629 次

深入理解linux内核笔记

1 linux在内存管理模块,为了解决外部碎片的问题,采用了Buddy System Algorithm。

所有的连续free page被分成11个组,每个组是一个块列表(块表示一个连续的未分配page区域)。每个列表的连续块大小分别是1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 到1024个page。

当请求一个256page的内存区域时,会先到256的这个列表里查找,如果能够找到一个256的空闲内存区域,那么直接返回;如果找不到,那么到更大的512列表里找,如果存在,那么返回256个page给请求,并把剩余的连续256个page的块分配到256列表;如果512列表找不到,那么继续往上找1024,如果1024也没有,那么返回内存分配失败。

http://ilinuxkernel.com/?p=1029

http://www.csdn123.com/html/blogs/20130607/20419.htm

尽管采用虚拟内存技术,连续的虚拟内存不一定得对应连续的物理内存。但是还是有一些原因要求内核在分配内存的时候必须要采用连续的物理内存,有这么几个原因:

?? In some cases, contiguous page frames are really necessary, because contiguous?linear addresses are not sufficient to satisfy the request. A typical example is a?memory request for buffers to be assigned to a DMA processor (see Chapter 13).?Because most DMAs ignore the paging circuitry and access the address bus?directly while transferring several disk sectors in a single I/O operation, the buffers requested must be located in contiguous page frames.

? Even if contiguous page frame allocation is not strictly necessary, it offers the big?advantage of leaving the kernel paging tables unchanged. What’s wrong with?modifying the Page Tables? As we know from Chapter 2, frequent Page Table?modifications lead to higher average memory access times, because they make?the CPU flush the contents of the translation lookaside buffers.

? Large chunks of contiguous physical memory can be accessed by the kernel?through 4 MB pages. This reduces the translation lookaside buffers misses, thus

significantly speeding up the average memory access time (see the section

“Translation Lookaside Buffers (TLB)” in Chapter 2).

?

2 内存分配请求可以通过两种方式来满足,一种是如果有free page那么直接分配返回;如果没有free page那么阻塞请求,触发内存回收,直到有空闲的内存区域,才返回分配请求。

但是一些内存分配请求不允许阻塞,比如中断例程、执行临界区的请求。这个时候就需要一种非阻塞的内存请求机制-原子内存分配,如果没有可用内存区域,不阻塞,直接返回失败;但是操作系统还是会尽可能的保证请求成功,于是就有了一个系统保留页区域,这个区域的page由ZONE_DMA、ZONE_NORMAL贡献。当可用内存不足时,原子内存分配请求会使用这个保留区域的page。

?

3 尽管Buddy System Algorithm可以解决外部碎片的问题,但是依然没法解决内部碎片。内存管理的最小分配单位是页,页的尺寸一般为4kb,如果遇到小内存空间的请求,比如几十到几百byte,每次都分配一个完整的页,那么势必会造成很严重的内存碎片。于是就有了slab allocator,他是基于Buddy System上的一层逻辑

?http://en.wikipedia.org/wiki/Slab_allocation

使用Slab allocation有几个前提:分配的数据类型影响内存分配的特点,可以把分配的数据抽象成一类对象;用户会频繁的对同一类对象进行内存分配请求;对内存区域的请求可以按照频繁度分类;为了提高cpu cache的命中率,要尽量减少对buddy system allocator的请求,以免出现太多脏缓存。

slab allocator按照同类对象进行分组,放到缓存里(这里的缓存是指已经预先经过buddy system allocator

分配过page的内存区域)。每一个缓存都是同一类对象的仓库。缓存被划分成一个个slab。每个slab都有一个或者多个连续的page frame组成,slab里面放同一类的对象,同一类的对象对内存的占用大小类似。当一个对象被释放后,内存并不会被操作系统回收,而是在下次分配同一类对象的时候,直接复