linux 内存管理slab源码,Linux内核源代码情景分析-内存管理之slab-回收
图 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-回收相关推荐
- Linux内核源代码情景分析-内存管理
用户空间的页面有下面几种: 1.普通的用户空间页面,包括进程的代码段.数据段.堆栈段.以及动态分配的"存储堆". 2.通过系统调用mmap()映射到用户空间的已打开文件的内容. 3 ...
- Linux内核源代码情景分析笔记
Linux内核源代码情景分析笔记 好吧,首先我承认我要是读者的话,这篇文章我看着也头疼,因为写的太长太泛(其主要部分集中在内存管理,进程管理,文件系统)!原本是想按自己理解的精简精简的,按照操作系统中 ...
- Linux 内核源代码情景分析(二)
系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核 Linux 设备驱动程序 Linux设备驱动开发详解 深入理解Linux虚拟内存管理 Linux 内核源代码情景分析(一) Lin ...
- Linux内核源代码情景分析-nanosleep()和pause()
我们介绍nanosleep()和pause()两个系统调用. 系统调用nanosleep()在内核中的实现为sys_nanosleep(),代码如下: asmlinkage long sys_nano ...
- linux的v4l2运行源码,linux v4l2摄像头应用层编程介绍
一.前言 最近项目需要做一个工业条形读码器,在底层应该会适配linux v4l2框架,就自己研究了一下在应用层怎么使用v4l2进行编程,查阅了相关资料,主要是网上的博客资料,有: https://ww ...
- linux如何运行qt源码,Linux/Ubuntu下编译Qt4.8.2源码
本人所用的系统为Ubuntu 14,所下载的QT源码版本为4.8.2. 以下是编译QT源码的基本步骤: 2.解压代码 输入指令: tar zxvf qt-everywhere-opensource-s ...
- Linux内核源代码情景分析-fork()
父进程fork子进程: child = fork() fork经过系统调用.来到了sys_fork.具体过程请參考Linux内核源码情景分析-系统调用. asmlinkage int sys_fork ...
- linux内核源代码情景分析(第一章 预备知识)
第一章 预备知识 1.1 linux内核简介 linux发展路线图 linux目录结构 GPL许可证 GPL条款规定GNU软件以及GNU软件的基础上加以修改而成的软件,在发布.转让.出售时必须要申明该 ...
- 社会管理网格化 源码_天津市红桥区社会治理网格化管理平台获CIO智选政务应用奖...
近日,在中央专业媒体集团计世传媒推出的"2020 CIO领航计划"暨"复工复产复学优秀案例征集大型活动"中,中国系统与天津市红桥区网格化管理中心联合申报的&qu ...
最新文章
- Poj(1703),种类并查集
- ThreadPoolTaskExecutor使用详解
- Matlab | Matlab从入门到放弃(8)——线性代数
- android ros 节点编写_嵌入式的我们为什么要学ROS
- 用 Ansible 实现基于 OpenShift (Kubernetes) 的 DevOps
- 201触摸ic应用电路_PCB板和集成电路的区别有哪些
- 用数字化数据战略取代数据“收集和管理”
- 安卓手机上微信无法打开Https网址的完美解决方案
- Java中getclass(),class()与iinstanceof的区别与联系
- ASP.NET Core--授权过滤器
- Activity 的启动模式
- Markdown 使用感受
- rapidxml 文件读写,增加删除节点
- 用c语言算法统宗 李白沽酒,趣味数学题:百羊问题与李白沽酒
- ESP8266获取B站粉丝数
- gps测试软件用法,gps测量仪器使用方法及教程
- 腾讯云https证书部署nginx
- ibatis中配置parameterClass=java.util.HashMap的用法
- 2019python下半年考试报名时间_【2019下半年CATTI考试报名时间汇总】- 环球网校
- 《奇点临近》的一些优秀读后感
热门文章
- 使用 Trace32 对 FLASH 编程
- 一文运维zookeeper
- ab测试nginx Nginx性能优化
- spring boot 服务 正确关闭方式
- -bash:syntax error near unexpected token '('
- [转载]Matlab之静态文本多行输出
- 基于node.js的压缩合并安装
- [转载]Oracle 11g新特征之形式料理(2)
- 算法:详解布隆过滤器的原理、使用场景和注意事项@知乎.Young Chen
- xauth: (stdin):1: bad display name LSPPC-Lenny:1 in add command