SLAB和内存泄露

11 篇文章 0 订阅
8 篇文章 0 订阅

背景:

事情是这样来的,测压力测试,发现内存在缓慢上涨(一天涨5MB左右),坑D了,已经用mleak扫描过,内核模块不应该有泄露。

然后开始往细节上学习linux内存知识。

经过几天学习,找各种资料和书来看slab什么的。算是有所掌握了slab。怕时间一久自己给忘记了,故写下一些杂言,帮助将来快速恢复。

 

几个问题:

1.内存回收,dcache,slab 回收,它们是个啥关系,基本机制是啥?

 

slab本身

学习的过程,非常像盲人摸象的过程。有好几个方面,单独抽一个部分来学,并不好学,也不明白。但是有时候又不得不从部分学起,直到该有的都知道了,一个干净

纯洁的东西,出现了。简化时就是一个最基础模型,扩展开来就是完整的全部。哪个部分是为什么而来,有什么好处都清楚知道。哪个部件负责什么,边界又是什么也清楚。从问题答案角度来讲,学的时候有许多问题,学完应该都能回答。

Q1: slab最基础的结构模型是啥?

我们从最基础的slab一步步来搭出kernel现在的slab.

1.slab就是一个包含多个obj的内存页组,然后多个slab构成一个list.

2.由于存在3类slab状态,full.partial,free。所以整了3个list来加速。

 struct kmem_cache_node {

    struct list_head slabs_partial;    /* partial list first, better asm code */
    struct list_head slabs_full;
    struct list_head slabs_free;

}

3.然后多个不同名字的slab构成slab_chain.

4.这个版本太简单了,得填充细节,优化性能。

由于buddy系统是page^order来分配page的,所以slab是以gfporder来申请释放内存页的。

struct kmem_cache {

unsigned int gfporder;

}

这样slab内部是连续的内存块,可以紧凑的放下多个obj。如何有效管理slab的obj了?考虑数据的warm热性,LIFO先进后出性能最好,因为它更可能在cache上,缩短load时间。用一个stack是合适的,最初的slab就是用的list链表,不过linux使用array数组来实现stack,因为真的不需要伸缩。一个数组加一个index就能构成stack。

struct slab {

kmem_bufctl_t free; 这个就是stack栈索引,SP。

它的运行机制有点小技巧,是用数字表示obj位置,存在index->obj addr的转换。还用负数表示BUFCTL_END ,BUFCTL_FREE

}

数组在哪了?它本身在初始化时动态分配大小。因此没有出现在slab,而是在slab之后。

static inline kmem_bufctl_t *slab_bufctl(struct slab *slabp)
{
    return (kmem_bufctl_t *) (slabp + 1);
}

这样就高效的管理了free obj了。如何初始化stack,这个真不用太看。

5. slab着色 

slab color听起来是不是高大上,有点玄乎?其实它从内容上看并不多,也不难。属于性能优化。

简单点讲,就是对象本来都是整整齐齐的分布在slab上。这不利于CPU cache line:cache line希望你们不要占同一个地址的坑。最好是分布在不同的cache line上。

着色就是:如果可以,就将slab上的对象组整体以cache line(通常64B)进行填充偏移。这个每个slab上的obj起始位置将均匀分布在不同的cache line上。

理论分析解释:

1.CPU现在有L1,L2,L3级缓存,每个数据是以cache line进行操作的,由于cache比主存小很多,就必然有替换算法。由于数据和指令的相邻效应,相应cache line地址肯定不会冲突。局部性是要优先保证的。造成cache冲突的是非局部性地址块(局部性大小=total cache size/N-way),主流的是N-way组相联,本质就是地址hash后,hash地址冲突的定长为N的链表。

2.)对全相联的确是没有作用。

3.)对组相联cache来说,作用还是有的,首先slab的obj数据里面也是有热点区域,如果着色,比如一个热点区数据,如果不着色,理想的cache冲突深度为N-way。如果着色有一个cache size的偏移,假设obj数量很多,概率是均匀分布(因为slab就是顺序来填的)。那么着色收益,将是cache冲突深度为2*N-way。相当于将CPU硬件的N-way,比如8路组相联变成16路组相联。提高了热点数据的容纳深度(也可以理解为宽度,因为它真的是热点数据移动到旁边的坑里,占了更的的坑)。

6. slab这一层就2个东西:着色,LIFO先进后管理空闲obj. 还有一个使用计数unsigned int inuse方便管理状态,用空就去full list,没用一个自然是free list。

7. per CPU多核加速的stack free obj 

 struct array_cache {

    unsigned int limit; stack top

 unsigned int avail; SP
    void *entry[];  stack数组

}

多核已经是主流,为了降低并发访问的开销,无锁的per CPU方案自然是更好的选择(就是每个CPU使用自己专用的slab list,是不是听起来很爽)。不过了,由于linux支持

抢占,所以还有一个锁来防止抢占。slab为每个CPU分配一个array_cache。里面配置一个数组来缓存free的obj。为了用上cache-warm objects,数组还是LIFO机制的栈,SP是ac->avail。注意这个SP指向的是void *,比slab里的stack要省事,直接指向对象obj。

还要注意一点:obj放回slab list时,要obj addr->slab的转换。利用obj->page->slab的方法。

page结构体太难了,对于不同的page应用,page有多种身份。其实struct page是个union多态。如此紧凑的struct page内存使用,真的是C语言系才能胜任。

slabp = virt_to_slab(objp);

static inline struct slab *virt_to_slab(const void *obj)
{
    struct page *page = virt_to_head_page(obj);  
    return page->slab_page; 我struct page里面还在了slab 相关的数据指针,666
}

然后unsigned int batchcount;来了。当stack满了时,一次批量将obj释放回slab的数量。这样是不是比一个一个释放要高效。

8 生长和回收

当slab obj没有了,就要从buddy中申请。grow倒没什么好说的。

回收reclaim是重点,也是难点。这有个性能平衡的考虑。过于激进的回收释放page,free内存是多了,但是重新申请时,又有时间上的开销。

1.struct kmem_cache_node { unsigned long free_objects;unsigned int free_limit; } 当一个slab是free的,同时 free_objects>free_limit,就释放这个slab回buddy.

2.shrink_slab()是一个重要的入口,dentry cache,inode cache之类可以shrink的会被调用各自的shrnker,释放自己的slab obj回到slab.然后slab内部释放page.

可以看到shrink只有通知建议权,如何释放归各使用都自己管。

好像完了。

 

Q2: slab内存回收是啥?slab可回收和不可回收有啥区别?

这个问题最坑爹了,不敢说能回答对,就目前而言:它们真没啥区别!唯一的区别就是显示时分类下,安慰一下user。可回收slab几乎全部和文件系统VFS有关:主要是dentry,inode。然而可回收也只能把没有用的dentry,inode给释放,如果在使用中,也是不可能回收滴。

在我没有学完前,一度以为SLAB_RECLAIM_ACCOUNT会有什么黑魔法,有啥激进的回收策略。现在看起来,真的只是用来标识分类。不用没有任何区别。不会少回收内存。

Q3,dentry cache,inode cache是如何回收?

dentry有4种状态,in used, no used,negative,free. 当不在inused时,会被放入LRU中,当系统要回收时,会通知dcache释放时,它选择要释放的dentry回到slab.

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值