注:本文分析基于3.10.0-693.el7内核版本,即CentOS 7.4

1、关于drop_caches

通常在内存不足时,我们习惯通过echo 3 > /proc/sys/vm/drop_caches 的方式手动清理系统缓存,

[root@localhost  ~]# free -mtotal        used        free      shared  buff/cache   available
Mem:           7822        3436        2068          40        2317        3997
Swap:             0           0           0
[root@localhost  ~]# echo 3 > /proc/sys/vm/drop_caches
[root@localhost ~]# free -mtotal        used        free      shared  buff/cache   available
Mem:           7822        3433        4036          40         352        4037
Swap:             0           0           0

对于数字3的含义,我们可以通过内核文档了解其具体含义,

To free pagecache: echo 1 > /proc/sys/vm/drop_caches
To free reclaimable slab objects (includes dentries and inodes): echo 2 > /proc/sys/vm/drop_caches
To free slab objects and pagecache: echo 3 > /proc/sys/vm/drop_caches

2、释放pagecache

在之前我们知道当内存低于某个阈值时,会触发脏页回写,提交回写work到对应BDI设备上,由BDI writebacke进程回写脏页释放内存。这和drop_caches中的echo 1类似,都是释放脏页,因此其最后路径是一致的。

int drop_caches_sysctl_handler(ctl_table *table, int write,void __user *buffer, size_t *length, loff_t *ppos)
{int ret;ret = proc_dointvec_minmax(table, write, buffer, length, ppos);if (ret)return ret;if (write) {static int stfu;// echo 1 > drop_cachesif (sysctl_drop_caches & 1) {iterate_supers(drop_pagecache_sb, NULL);count_vm_event(DROP_PAGECACHE);}// echo 2 > drop_cachesif (sysctl_drop_caches & 2) {drop_slab();count_vm_event(DROP_SLAB);}if (!stfu) {pr_info("%s (%d): drop_caches: %d\n",current->comm, task_pid_nr(current),sysctl_drop_caches);}//置位,否则就一直在回收了stfu |= sysctl_drop_caches & 4;}return 0;
}

可见,echo 1时,会调用drop_pagecache_sb去释放pagecache,我们继续往下查,

drop_pagecache_sb ->iput ->iput_final->write_inode_now -> #提交writeback_control,立即回写writeback_single_inode ->__writeback_single_inode ->do_writepages #调用对应文件系统的writepage写回磁盘

在BDI回写里,一开始提交的是wb_writeback_work,等到实际要执行回写操作时,都会转换为writeback_control,再去执行回写。

因此,echo 1的操作就是,遍历每个超级块,调用drop_pagecache_sb,drop_pagecache_sb中会遍历该超级块所有的inode,对其关联的pagecache进行回写。与BDI不同的是,该操作是立马执行,不需要等待周期执行或者inode过期。

3、释放slab cache

而对于echo 2的情况,就比较复杂一点,

static void drop_slab(void)
{int nr_objects;struct shrink_control shrink = {.gfp_mask = GFP_KERNEL,};//上次回收缓存数量高于10,就再进行一次回收//这个条件其实挺苛刻的,回收后整个系统空闲slab不会超过10do {nr_objects = shrink_slab(&shrink, 1000, 1000);} while (nr_objects > 10);
}unsigned long shrink_slab(struct shrink_control *shrink,unsigned long nr_pages_scanned,unsigned long lru_pages)
{struct shrinker *shrinker;unsigned long ret = 0;...//遍历系统中所有的shrinker,回收各个slab管理区的空闲缓存list_for_each_entry(shrinker, &shrinker_list, list) {unsigned long long delta;long total_scan;long max_pass;int shrink_ret = 0;long nr;long new_nr;//获取批处理数量,默认每次回收128,对于超级块而言是1024long batch_size = shrinker->batch ? shrinker->batch: SHRINK_BATCH;//获取该slab管理区可回收的缓存数量max_pass = do_shrinker_shrink(shrinker, shrink, 0);if (max_pass <= 0)continue;nr = atomic_long_xchg(&shrinker->nr_in_batch, 0);total_scan = nr;//计算该slab管理区此次缓存回收额度,一堆操作//针对手动释放缓存的场景,基本上是两倍的max_pass,也就是尽可能去释放//对于kswap或其他路径上,不会超过一倍的max_passdelta = (4 * nr_pages_scanned) / shrinker->seeks;delta *= max_pass;do_div(delta, lru_pages + 1);total_scan += delta;if (total_scan < 0) {printk(KERN_ERR "shrink_slab: %pF negative objects to ""delete nr=%ld\n",shrinker->shrink, total_scan);total_scan = max_pass;}//如果delta偏小,意味着系统中inactive的缓存偏少,我们回收的额度也不能设置太大if (delta < max_pass / 4)total_scan = min(total_scan, max_pass / 2);//控制回收总额上限,避免死循环if (total_scan > max_pass * 2)total_scan = max_pass * 2;trace_mm_shrink_slab_start(shrinker, shrink, nr,nr_pages_scanned, lru_pages,max_pass, delta, total_scan);//循环回收缓存while (total_scan >= batch_size) {int nr_before;//记录处理前缓存数量nr_before = do_shrinker_shrink(shrinker, shrink, 0);//回收后缓存数量shrink_ret = do_shrinker_shrink(shrinker, shrink,batch_size);if (shrink_ret == -1)break;//统计此次回收的缓存数量if (shrink_ret < nr_before)ret += nr_before - shrink_ret;count_vm_events(SLABS_SCANNED, batch_size);//减少扫描总额total_scan -= batch_size;cond_resched();}//如果剩下的额度不够一个batch_size,留着下次使用,记录在nr_in_batchif (total_scan > 0)new_nr = atomic_long_add_return(total_scan,&shrinker->nr_in_batch);elsenew_nr = atomic_long_read(&shrinker->nr_in_batch);trace_mm_shrink_slab_end(shrinker, shrink_ret, nr, new_nr);}up_read(&shrinker_rwsem);
out:cond_resched();return ret;
}

空闲slab缓存计算和回收都是在do_shrinker_shrink完成,它其实调用的是一个函数指针,不同slab管理区有自己定义的shrink函数,第三个入参nr_to_scan为0时,是计算空闲slab缓存;不为空时,表示扫描和回收缓存的数量。

static inline int do_shrinker_shrink(struct shrinker *shrinker,struct shrink_control *sc,unsigned long nr_to_scan)
{int objects;sc->nr_to_scan = nr_to_scan;objects = (*shrinker->shrink)(shrinker, sc);if (objects < -1)return INT_MAX;return objects;
}

总的来说,drop_slab就是调用每个slab管理区定义的shrink函数,先计算出可回收的slab缓存数量,然后确定扫描数量,最后调用shrink函数执行缓存扫描和回收。

vm内核参数之缓存回收drop_caches相关推荐

  1. vm内核参数优化设置

    http://www.cnblogs.com/wjoyxt/archive/2014/06/08/3777042.html (1)vm.overcommit_memory 执行grep -i comm ...

  2. vm内核参数之内存脏页dirty_writeback_centisecs和dirty_expire_centisecs

    注:本文分析基于3.10.0-693.el7内核版本,即CentOS 7.4 1.背景 在<BDI writeback脏页回写>中我们了解了BDI的一些基本结构以及初始化和一些触发路径,现 ...

  3. 谨慎调整内核参数:vm.min_free_kbytes

    内核参数:内存相关 内存管理从三个层次管理内存,分别是node, zone ,page; 64位的x86物理机内存从高地址到低地址分为: Normal DMA32 DMA.随着地址降低. [root@ ...

  4. linux内核参数详解

    kernel.acct acct功能用于系统记录进程信息,正常结束的进程都会在该文件尾添加对应的信息.异常结束是指重启或其它致命的系统问题,不能够记录永不停止的进程.该设置需要配置三个值,分别是: 1 ...

  5. /proc/sys/vm虚拟内存参数

    1.admin_reserve_kbytes 给有cap_sys_admin权限的用户保留的内存数量,默认值是min(free pages * 3%, 8MB).这些内存是为了给管理员登录和杀死进程恢 ...

  6. Linux内核参数解释

    第1章 内核参数说明 1.1 内核参数列表 kernel.acct acct功能用于系统记录进程信息,正常结束的进程都会在该文件尾添加对应的信息.异常结束是指重启或其它致命的系统问题,不能够记录永不停 ...

  7. 关于linux内存管理相关的内核参数

    最近闲来无事,就打算整理一下linux内存管理相关的内核参数,以便以后查阅使用.在整理的过程中除了参考内核文档Document/sysctl/vm.txt之外,更多的是参考网上的各位大神写的资料,大部 ...

  8. Centos内核参数

    内核参数 abi.vsyscall32 = 1  在2.6.25版本以后的x86-64内核中,默认启用了VDSO32. 虚拟动态共享对象 http://man7.org/linux/man-pages ...

  9. linux内核参数汇总

    目录: 目录 linux内核参数配置 内核参数列表 内存参数列表 网络参数列表 linux内核参数配置 Linux在系统运行时修改内核参数(/proc/sys与/etc/sysctl.conf),而不 ...

  10. Linux命令05 - - sysctl 配置内核参数

    内核参数 1.sysctl 命令 1.功能:用于在内核运行时动态地修改内核的运行参数,可用的内核参数在目录"/proc/sys" 2.特点:它包含一些TCP/ip堆栈和虚拟内存系统 ...

最新文章

  1. DevOps 的发展史
  2. python教学在线观看-python在线学习
  3. Genymotion-启动报错Unable to load VirtualBox engine....
  4. 深度学习在自然语言处理的应用(Version 0.76)
  5. 关于linux kernel编译的几项关键点:
  6. fastai学习:05_pet_breeds Questionnaire
  7. mac下一些终端命令的使用
  8. 升级域控制器-从Windows 2012升级到2016案例之1
  9. dw代码能在php运行吗,php新手求助,为什么在DW中设计里能看到运行php程序的结果,但…...
  10. 深入理解Flink ---- 系统内部消息传递的exactly once语义
  11. Julia: 奇技淫巧......
  12. ideal pom文件安装到maven库中_不装 maven 直接使用 IntelliJ 的插件来把本地 jar 包加入到 maven 仓库...
  13. 使用FileUpload控件上传文件时对文件大小的限制
  14. 半导体丨索尼推出世界最小监控用CMOS图像传感器IMX415
  15. keil5写c语言的步骤,keil5使用C51的详细步骤讲述
  16. 关于ModifyStyle
  17. Python分析《哈哈哈哈哈》4万弹幕
  18. java 线程强制执行join
  19. 【编译系统】什么是PL/0和类Pcode虚拟机
  20. 再见深圳!我要去成都搞IT了!

热门文章

  1. 基于哈夫曼编码的文件压缩
  2. 负反馈放大电路的四种组态
  3. 计算机软件著作权可以同时寄多份,软件著作权可以挂几个人,最多几个作者?...
  4. 无线路由器的信道选择
  5. 阿里云和AWS对比研究三——存储产品对比
  6. 阿里巴巴的图标库 -------------本地使用
  7. Python简单换脸程序
  8. 人民币符号是什么 人民币符号怎么打
  9. 账结法 表结法 两种财务会计处理方法
  10. 六、CSS3的美化字体与段落