为了技术,我不会停下学习的脚步,我相信我还能走二十年。
分类: LINUX
2013-02-28 11:12:40
原文地址:slub源码分析 作者:liujunwei1234
总结起来,SLAB太过复杂,光是用在这套机制的管理上开销就很大(时间和空间),导致性能较差,而且,代码很难维护。
二 SLUB涉及的主要数据结构
1 kmem_cache: slab的描述结构,即每一个slab对应一个kmem_cache数据结构来描述
2 page:每一个物理页框(page frame)对应的描述结构,一般称作页
3 object: 某一类特定的对象,比如进程描述符task_struct, 文件指针FILE等等
4 kmem_cache_cpu:每一个cpu对应的一个结构,起始他也是一个slab,可以理解为每
cpu的slab,主要是为了smp时多个核可以并行访问自己的slab。
5 kmem_cache_node: 每个内存节点(node)的slab描述,在 SLUB 中,没有单独的 Empty slab 队列。每个 NUMA 节点使用 kmem_cache_node 结构维护一个处于 Partial 状态的 slab 队列。(这个理解有点模糊)
三 各结构之间的关系
1 每个page至少包含两个object,否则内核将会按页分配内存。
2 一个slab至少占用一个page,否则,将会出现同一页中至少有两种不同类型的object。
3 每一个slab还指向一个kmem_cache_node和一个kmem_cache_cpu结构(UP情况下)
4 内核在启动初始化的过程中,默认初始化11个slab,即kmem_caches[12]数组。
四 SLUB初始化
在start_kernel函数中调用下面函数对11个slab进行初始化,这里只是初始化数据结构,并没有真正的申请物理页框。
void __init kmem_cache_init(void)
{
int i;
int caches = 0;
init_alloc_cpu();
/* Able to allocate the per node structures */
slab_state = PARTIAL;
/* Caches that are not of the two-to-the-power-of size */
if (KMALLOC_MIN_SIZE <= 64) {
create_kmalloc_cache(&kmalloc_caches[1],
"kmalloc-96", 96, GFP_KERNEL);
caches++;
}
if (KMALLOC_MIN_SIZE <= 128) {
create_kmalloc_cache(&kmalloc_caches[2],
"kmalloc-192", 192, GFP_KERNEL);
caches++;
}
for (i = KMALLOC_SHIFT_LOW; i < PAGE_SHIFT; i++) {
create_kmalloc_cache(&kmalloc_caches[i],
"kmalloc", 1 << i, GFP_KERNEL);
caches++;
}
... ... ... ...
}
五 SLUB的内存分配(UP情况下)
先大体讲一下整个分配的过程:
1 根据申请的内存大小,假设为size字节,如果size > PAGE_SIZE/2, 就直接分配一页,否则,到kmem_caches[12]中寻找最合适的slab。
2 因为在SLUB的初始化的时候,并没有真正的分配页框,所以在第一次申请内存的时候才去做这个操作。首先,检查每cpu的slab的freelist,即kmem_cache_cpu.freelist,因为是第一次肯定是空的
3 再去检查每个node的partial链表,即kmem_cache_node.partial,此时肯定也是空的。
4 从buddy系统中分配2^order个页框,order是在kmem_cache中指定的,并把这些页框初始化成大小为size的object,并初始化响应的数据结构。
5 将分配到的2^order个页框第一个页框对应的page->freelist=object,即指向第一个object对象。并将page结构中的inuse赋值为这个页框包含的object的数量
6 分配出第一个object,然后将page->freelist=NULL, 将每cpu的slab的freelist赋值为第二个object的地址。(kmem_cache_cpu.freelist = object[offset])
以后再有这种大小的object的请求,就会直接从每cpu的slab的freelist上分配。
六 SLUB的内存释放
假设释放地址为x的某个object。
1 通过虚拟地址或先行地址x,可以得到该object属于哪个page,进而通过page->slab可以得到该object属于哪个slab。
2 如果当前slab的page指针,即kmem_cache_cpu.page等于要释放的object属于的page,那么,就直接把object释放到kmem_cache_cpu.freelist中。
3 否则,page->inuse--,然后把object属于的page添加到kmem_cache_node的partial中。
以上部分就是我对SLUB算法的简单的理解。
红字部分是我不理解的,只是看代码是这样做的,哪位大哥能给解释下,同样的是,为什么每次分配的时候回去查看这个partial链表,我就是有点想不通,partial到底扮演了什么角色。