图 1

我们看到空闲slab块占用的若干页面,不会自己释放;我们是通过kmem_cache_reap和kmem_cache_shrink来回收的。他们的区别是:

1、我们先看kmem_cache_shrink,代码如下:

int kmem_cache_shrink(kmem_cache_t *cachep)

{

if (!cachep || in_interrupt() || !is_chained_kmem_cache(cachep))

BUG();

return __kmem_cache_shrink(cachep);

}

__kmem_cache_shrink,代码如下:

static int __kmem_cache_shrink(kmem_cache_t *cachep)

{

slab_t *slabp;

int ret;

drain_cpu_caches(cachep);

spin_lock_irq(&cachep->spinlock);

/* If the cache is growing, stop shrinking. */

while (!cachep->growing) {//确定缓存区不在growing

struct list_head *p;

p = cachep->slabs.prev;//链表最后面的是空闲块,本例中就是第4个空闲块

if (p == &cachep->slabs)//如果链表中没有slab块,就直接break

break;

slabp = list_entry(cachep->slabs.prev, slab_t, list);

if (slabp->inuse)//如果不是空闲块,就break

break;

list_del(&slabp->list);//如果是空闲块就删除,这样下一次循环cachep->slabs.prev找的就是新的slab块

if (cachep->firstnotfull == &slabp->list)//如果firstnotfull就是这个空闲块,那么系统中一定没有部分块或者空闲块可供分配了

cachep->firstnotfull = &cachep->slabs;//指向cachep->slabs

spin_unlock_irq(&cachep->spinlock);

kmem_slab_destroy(cachep, slabp);//析构对象,并释放空闲slab块所在的所有页面

spin_lock_irq(&cachep->spinlock);

}

ret = !list_empty(&cachep->slabs);

spin_unlock_irq(&cachep->spinlock);

return ret;

}

kmem_slab_destroy,析构对象,并释放空闲slab块所在的所有页面,代码如下:

static void kmem_slab_destroy (kmem_cache_t *cachep, slab_t *slabp)

{

if (cachep->dtor

......

) {

int i;

for (i = 0; i < cachep->num; i++) {

void* objp = slabp->s_mem+cachep->objsize*i;

......

if (cachep->dtor)

(cachep->dtor)(objp, cachep, 0);//析构所有对象

......

}

}

kmem_freepages(cachep, slabp->s_mem-slabp->colouroff);//释放空闲slab块所占的所有页面

if (OFF_SLAB(cachep))

kmem_cache_free(cachep->slabp_cache, slabp);

}

kmem_freepages,释放空闲slab块所占的所有页面,代码如下:

static inline void kmem_freepages (kmem_cache_t *cachep, void *addr)

{

unsigned long i = (1<gfporder);

struct page *page = virt_to_page(addr);

/* free_pages() does not clear the type bit - we do that.

* The pages have been unlinked from their cache-slab,

* but their 'struct page's might be accessed in

* vm_scan(). Shouldn't be a worry.

*/

while (i--) {

PageClearSlab(page);

page++;

}

free_pages((unsigned long)addr, cachep->gfporder);

}

2、再看kmem_cache_reap,遍历cache_chain链表查找合适的缓存区,而且只释放了所选中的缓存区中最多80%的完全空闲slab块,代码如下:

void kmem_cache_reap (int gfp_mask)

{

slab_t *slabp;

kmem_cache_t *searchp;

kmem_cache_t *best_cachep;

unsigned int best_pages;

unsigned int best_len;

unsigned int scan;

if (gfp_mask & __GFP_WAIT)

down(&cache_chain_sem);

else

if (down_trylock(&cache_chain_sem))

return;

scan = REAP_SCANLEN;

best_len = 0;

best_pages = 0;

best_cachep = NULL;

searchp = clock_searchp;//上一次考察的缓存区

do {

unsigned int pages;

struct list_head* p;

unsigned int full_free;

/* It's safe to test this without holding the cache-lock. */

if (searchp->flags & SLAB_NO_REAP)

goto next;

spin_lock_irq(&searchp->spinlock);

if (searchp->growing)//缓存区不能处于增长状态

goto next_unlock;

if (searchp->dflags & DFLGS_GROWN) {

searchp->dflags &= ~DFLGS_GROWN;

goto next_unlock;

}

......

full_free = 0;

p = searchp->slabs.prev;//从空闲块开始

while (p != &searchp->slabs) {

slabp = list_entry(p, slab_t, list);

if (slabp->inuse)

break;

full_free++;//有一个空闲块,full_free就加1

p = p->prev;//往前继续搜索

}

/*

* Try to avoid slabs with constructors and/or

* more than one page per slab (as it can be difficult

* to get high orders from gfp()).

*/

pages = full_free * (1<gfporder);//若干空闲块所占的页面数

if (searchp->ctor)

pages = (pages*4+1)/5;

if (searchp->gfporder)

pages = (pages*4+1)/5;//页面数的百分之80

if (pages > best_pages) {//找到空闲块所占页面数最多的

best_cachep = searchp;

best_len = full_free;//空闲块的个数

best_pages = pages;//若干空闲块所占的页面数的百分之80

if (full_free >= REAP_PERFECT) {

clock_searchp = list_entry(searchp->next.next,

kmem_cache_t,next);

goto perfect;

}

}

next_unlock:

spin_unlock_irq(&searchp->spinlock);

next:

searchp = list_entry(searchp->next.next,kmem_cache_t,next);

} while (--scan && searchp != clock_searchp);//遍历cache_chain链表查找合适的缓存区

clock_searchp = searchp;//这次考察的,也就是下次考察的开始

if (!best_cachep)//没有找到

/* couldn't find anything to reap */

goto out;

spin_lock_irq(&best_cachep->spinlock);

perfect:

/* free only 80% of the free slabs */

best_len = (best_len*4 + 1)/5;//空闲块个数的百分之80

for (scan = 0; scan < best_len; scan++) {//依次释放空闲块

struct list_head *p;

if (best_cachep->growing)//不能处于增长状态

break;

p = best_cachep->slabs.prev;//因为刚才空闲slab块已经删除,所以又指向了新的空闲slab块

if (p == &best_cachep->slabs)//说明所有slab块都已经被遍历过了,break

break;

slabp = list_entry(p,slab_t,list);

if (slabp->inuse)//不是空闲块,break

break;

list_del(&slabp->list);//删除空闲slab

if (best_cachep->firstnotfull == &slabp->list)//如果firstnotfull就是这个空闲块,那么系统中一定没有部分块或者空闲块可供分配了

best_cachep->firstnotfull = &best_cachep->slabs;//指向cachep->slabs

STATS_INC_REAPED(best_cachep);

/* Safe to drop the lock. The slab is no longer linked to the

* cache.

*/

spin_unlock_irq(&best_cachep->spinlock);

kmem_slab_destroy(best_cachep, slabp);//同上

spin_lock_irq(&best_cachep->spinlock);

}

spin_unlock_irq(&best_cachep->spinlock);

out:

up(&cache_chain_sem);

return;

}

linux 内存管理slab源码,Linux内核源代码情景分析-内存管理之slab-回收相关推荐

  1. Linux内核源代码情景分析-内存管理

    用户空间的页面有下面几种: 1.普通的用户空间页面,包括进程的代码段.数据段.堆栈段.以及动态分配的"存储堆". 2.通过系统调用mmap()映射到用户空间的已打开文件的内容. 3 ...

  2. Linux内核源代码情景分析笔记

    Linux内核源代码情景分析笔记 好吧,首先我承认我要是读者的话,这篇文章我看着也头疼,因为写的太长太泛(其主要部分集中在内存管理,进程管理,文件系统)!原本是想按自己理解的精简精简的,按照操作系统中 ...

  3. Linux 内核源代码情景分析(二)

    系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核 Linux 设备驱动程序 Linux设备驱动开发详解 深入理解Linux虚拟内存管理 Linux 内核源代码情景分析(一) Lin ...

  4. Linux内核源代码情景分析-nanosleep()和pause()

    我们介绍nanosleep()和pause()两个系统调用. 系统调用nanosleep()在内核中的实现为sys_nanosleep(),代码如下: asmlinkage long sys_nano ...

  5. linux的v4l2运行源码,linux v4l2摄像头应用层编程介绍

    一.前言 最近项目需要做一个工业条形读码器,在底层应该会适配linux v4l2框架,就自己研究了一下在应用层怎么使用v4l2进行编程,查阅了相关资料,主要是网上的博客资料,有: https://ww ...

  6. linux如何运行qt源码,Linux/Ubuntu下编译Qt4.8.2源码

    本人所用的系统为Ubuntu 14,所下载的QT源码版本为4.8.2. 以下是编译QT源码的基本步骤: 2.解压代码 输入指令: tar zxvf qt-everywhere-opensource-s ...

  7. Linux内核源代码情景分析-fork()

    父进程fork子进程: child = fork() fork经过系统调用.来到了sys_fork.具体过程请參考Linux内核源码情景分析-系统调用. asmlinkage int sys_fork ...

  8. linux内核源代码情景分析(第一章 预备知识)

    第一章 预备知识 1.1 linux内核简介 linux发展路线图 linux目录结构 GPL许可证 GPL条款规定GNU软件以及GNU软件的基础上加以修改而成的软件,在发布.转让.出售时必须要申明该 ...

  9. 社会管理网格化 源码_天津市红桥区社会治理网格化管理平台获CIO智选政务应用奖...

    近日,在中央专业媒体集团计世传媒推出的"2020 CIO领航计划"暨"复工复产复学优秀案例征集大型活动"中,中国系统与天津市红桥区网格化管理中心联合申报的&qu ...

最新文章

  1. Poj(1703),种类并查集
  2. ThreadPoolTaskExecutor使用详解
  3. Matlab | Matlab从入门到放弃(8)——线性代数
  4. android ros 节点编写_嵌入式的我们为什么要学ROS
  5. 用 Ansible 实现基于 OpenShift (Kubernetes) 的 DevOps
  6. 201触摸ic应用电路_PCB板和集成电路的区别有哪些
  7. 用数字化数据战略取代数据“收集和管理”
  8. 安卓手机上微信无法打开Https网址的完美解决方案
  9. Java中getclass(),class()与iinstanceof的区别与联系
  10. ASP.NET Core--授权过滤器
  11. Activity 的启动模式
  12. Markdown 使用感受
  13. rapidxml 文件读写,增加删除节点
  14. 用c语言算法统宗 李白沽酒,趣味数学题:百羊问题与李白沽酒
  15. ESP8266获取B站粉丝数
  16. gps测试软件用法,gps测量仪器使用方法及教程
  17. 腾讯云https证书部署nginx
  18. ibatis中配置parameterClass=java.util.HashMap的用法
  19. 2019python下半年考试报名时间_【2019下半年CATTI考试报名时间汇总】- 环球网校
  20. 《奇点临近》的一些优秀读后感

热门文章

  1. 使用 Trace32 对 FLASH 编程
  2. 一文运维zookeeper
  3. ab测试nginx Nginx性能优化
  4. spring boot 服务 正确关闭方式
  5. -bash:syntax error near unexpected token '('
  6. [转载]Matlab之静态文本多行输出
  7. 基于node.js的压缩合并安装
  8. [转载]Oracle 11g新特征之形式料理(2)
  9. 算法:详解布隆过滤器的原理、使用场景和注意事项@知乎.Young Chen
  10. xauth: (stdin):1: bad display name LSPPC-Lenny:1 in add command