- 论坛徽章:
- 0
|
对你的第一点部分同意.
我觉得首先要把内核中关于内存分配和释放的全过程弄清楚。
我比较喜欢从释放内存开始理解:
释放内存:
如一个skb, 当这个skb指针在多处保存,需要将skb->users引用计数+1, 即用skb_get(). 这样,当任务要释放skb的时候,调用kfree_skb(),这个函数会检查引用计数 skb->users是否为1,如果不是,直接返回,并不释放这块内存,否则,最终调用kfree()释放内存,
kfree() 要做以下事情:
1. 根据内存地址查找到对应的kmem_cache_t, 这个过程有一些优化,通过内存地址所在的物理页查找到对应的kmem_cache_t,在后面的内存分配会看到,当需要增加物理内存时,必须将整页内存分配个某个slab.
2. 将内存地址存放在kmem_cache_t->ac中的指定CPU cache数组中, 这时不会更新slab和kmem_cache_t->list->shared链表,除非下面的第二种情况出现. 所以slab 链表中,依然认为这块内存处于分配状态.
每个cpu有自己的ac cache, kfree()中的两种情况:
1. 正常释放到ac cache中.
2.当某个cpu的ac cache达到设定的上限值 ac->avail >ac->limit, 必须调用cache_flusharray()将ac->batchcount个obj从 ac 数组中转存到kmem_cache_t->lists->shared cache中.所以, shared cache充当了二次cache.
内存分配,当kmem_cache_t创建好的时候, 其中没有任何slab可用,分配第一个slab,会调用对应的分页算法分配物理页,每次必须分配整数个物理页,分页算法一般采用buddy算法.
kmalloc()分配算法: 如果是标准结构,如skb,
1. 从专用kmem_cache_t中分配, 先查找ac cache, 有可用的内存,直接将最后一个分配出去,否则
2. 从kmem_cache_t->lists->shared中转移batchcount 到指定cpu的ac cache中, 如果shared cache也没有可用obj
3. 从 partial slab 或者 free slab中分配内存, 如果没有可用slab
4. 调用分页算法添加新页到slab中.
上述过程中, 2~4必须锁kmem_cache_t中的自旋锁,所以多cpu不能同时进入.
如果是通用内存分配, 唯一的不同就是先要选择合适大小的kmem_cache_t cahce, 找到对应的kmem_cache_t后,直接按照上面的算法分配. 如果上述过程都是失败了(系统没有物理内存可用),在MMU cpu中,调用kswap任务,将内存 swap到磁盘上,空出可用物理内存页. 对于nommu cpu,返回NULL, 并提示出错,或者调用OOM killer
通过上面的过程可见,
1. ac cache中的obj 地址,不可能被多个cpu共用, kfree()执行不到,除非内核有bug. 也就是说,一旦进入ac cache后,这快内存一定是需要被释放的,其他cpu应该没有保存这个指针.
2. shared cache是作为一个二级cache使用的,这级cache不会刷回到slab中, 这是为了避免象网络这样的任务,一个cpu执行内核接收任务或者软中断接收分配300个skb或者更多,而另一个cpu执行发送,释放大量的skb,导致两个ac严重不平衡, shared缓存相当于一个蓄水池. 避免直接操作slab.
3. 至于0xbaadf00d, 我觉得只是一个maggic number, 这个值不会起任何作用. 因为shared不会刷回到slab中.
但是,当系统物理内存不够用时,内核会reap 所有的kmem_cache,这时 shared中的objs可能会释放.这个需要详细分析.
cheers!
[ 本帖最后由 xiaozhaoz 于 2006-1-23 19:24 编辑 ] |
|