内核把物理页作为内存管理的基本单位。对与4G内存的话,每一个物理页都对应了一个struct page结构体。Linux把系统的页分为几个区:ZONE_DMA,ZONE_NORMAL,ZONE_HIGHEM 。例如x86三个区就分别是< 16M,16-896M,>896M。内核地址空间是3-4G。低端内存是直接映射的,就是简单的加上偏移量,所以page结构体中直接返回其virtual成员就是虚拟地址了。而高端内存则是动态映射的,毕竟如果有那么大的物理内存的话,要保证内核能访问到所有的物理内存。
内核提供了分配页的接口函数:见P190(linux内核设计与实现)
对于kmalloc函数,是可以分配以字节为单位的一块内核内存,这个函数是建立在slab(或高级的slub)层上面的,底层实现也是页分配的,只不过将页划分为多个不同的对象,反正最后获得的就是所需要的字节大小。
不能给kmalloc和__get_free_pages等指定ZONE_HIGHMEN,因为这些函数都是返回虚拟地址的,而不是返回page结构指针的。像vmalloc才能,因为它会进行动态映射。而上述说的两个或更多,直接返回虚拟地址的函数,只直接返回page结构的虚拟地址成员,不会进行动态的映射,他们的虚拟地址只是简单的加上了偏移量。这两个或更多函数分配的内存当前可能还没有映射到内核的虚拟地址空间,所以,可能根本没有逻辑地址,即虚拟地址,所以可以认为kmalloc应该是在低端内存分配的(可以尝试当指定高端内存时候,内核会有什么反应。 另外alloc_pages()就可以分配高端内存了,因为其返回的是page结构)
vmalloc得到的就可能是高端内存也可能是低端内存。 他返回的地址就是上面的动态映射区
kmap函数实现的是永久映射,对应上面的kmap区,永久映射区
固定映射区的每个地址项都服务于特定的用途
vmalloc和malloc一样,申请时候都是只分了地址,实际内存是在实际访问的时候,才请页机制去分配内存的
对于slab层,一个高速缓存可以有多个slab(1-2个页),一个slab里面存了多个相同对象。
例如进程描述符结构,首先用kmem_cache_create创建一个高速缓存,其返回值即是高速缓存。然后利用kmem_cache_alloc从高速缓存中分配进程描述符一个这样的对像出来。用完的话,就用kmem_cache_free去释放,实际上仅仅是放回告诉缓存。 真正撤销高速缓存是用kmem_cache_destroy。 如果当在slab中找不到空闲的对象时候,就需要利用函数新建slab了,详细见p200左右波动的 slab章节