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

    最近闲来无事,就打算整理一下linux内存管理相关的内核参数,以便以后查阅使用。在整理的过程中除了参考内核文档Document/sysctl/vm.txt之外,更多的是参考网上的各位大神写的资料,大部分相关的解释都是直接复制粘贴的。尽管如此,也是在本人对这些解释真正理解了之后才搬过来的,算是做个记录,将来查阅的时候也能很快回忆起这些知识点,而不是看着一脸茫然。

    有些东西要解释起来需要大量的篇幅,就大概解释了下,然后给了个链接。本文中所提到的这些内核参数是在自己的机器上面看到的,内核版本为4.2.0-42。

vm.admin_reserve_kbytes = 8192    //系统为root用户的操作而保留的内存。为了避免系统内存完全用光导致root用户都无法登陆到机器进行trouble shooting,操作系统为root用户保留了一部分内存

vm.block_dump = 0    //开启这个选项,可以通过dmesg信息可以看到IO正在写那些文件,有进程号,inode号,文件名和磁盘设备名,但是感觉没什么用
vm.compact_unevictable_allowed = 1    //当需要进行页面合并时,是否允许合并不可回收的页面
vm.dirty_background_bytes = 0
vm.dirty_background_ratio = 10    //当用户调用write时,如果发现系统中的脏数据大于这阈值(或dirty_background_bytes ),会触发pdflush(writeback)进程去写脏数据,但是用户的write调用会立即返回,无需等待。pdflush(writeback)刷脏页的标准是让脏页降低到该阈值以下。dirty_background_ratio和dirty_background_bytes如果都设置,以dirty_background_ratio为准,以下同理。
vm.dirty_bytes = 0
vm.dirty_ratio = 20    //当用户调用write时,如果发现系统中的脏数据大于这阈值(或dirty_bytes ),需要自己把脏数据刷回磁盘,降低到这个阈值以下才返回。
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500    //该文件表示pdflush(writeback)进程的唤醒间隔,周期性把超过dirty_expire_centisecs时间的脏数据写回磁盘。

总的来说,就是达到dirty_background_ratio这个阈值时,会进行异步刷盘,而如果程序写入速度太快,比刷盘的速度还快,那么内存中脏数据的比例达到dirty_ratio这个阈值时,会进行同步刷盘,此时写操作会被阻塞,直到脏数据的比例低于dirty_ratio为止。要查看内存中当前有多少脏数据,可以使用grep -i dirty /proc/meminfo.

系统一般在下面三种情况下回写dirty页:
1.      定时方式: 定时回写是基于这样的原则:/proc/sys/vm/dirty_writeback_centisecs的值表示多长时间会启动回写线程,由这个定时器启动的回写线程只回写在内存中为dirty时间超过(/proc/sys/vm/dirty_expire_centisecs / 100)秒的页(这个值默认是3000,也就是30秒),一般情况下dirty_writeback_centisecs的值是500,也就是5秒,所以默认情况下系统会5秒钟启动一次回写线程,把dirty时间超过30秒的页回写,要注意的是,这种方式启动的回写线程只回写超时的dirty页,不会回写没超时的dirty页,可以通过修改/proc中的这两个值,细节查看内核函数wb_kupdate。
2.      内存不足的时候: 这时并不将所有的dirty页写到磁盘,而是每次写大概1024个页面,直到空闲页面满足需求为止
3.      写操作时发现脏页超过一定比例:
当脏页占系统内存的比例超过/proc/sys/vm/dirty_background_ratio 的时候,write系统调用会唤醒pdflush回写dirty page,直到脏页比例低于/proc/sys/vm/dirty_background_ratio,但write系统调用不会被阻塞,立即返回.
vm.dirtytime_expire_seconds = 43200     //目前没查到是什么意思

vm.drop_caches = 0    //清理内存cache,默认关闭

向/proc/sys/vm/drop_caches文件中写入数值可以使内核释放page cache,dentries和inodes缓存所占的内存。
只释放pagecache:
      echo 1 > /proc/sys/vm/drop_cache
只释放dentries和inodes缓存
      echo 2 > /proc/sys/vm/drop_caches
释放pagecache、dentries和inodes缓存
      echo 3 > /proc/sys/vm/drop_caches
这个操作不是破坏性操作,脏的对象(比如脏页)不会被释放,因此要首先运行sync命令。

vm.extfrag_threshold = 500     //当向伙伴系统申请一大段连续内存时,如果找不到符合条件的连续页, 于是触发了memory compaction.这个参数用来控制出现memory compaction的概率。它是一个0 ~ 1000的整数. 如果出现内存不够用的情况, Linux会为当前系统的内存碎片情况打一个分, 如果超过了extfrag_threshold这个值, kswapd就会触发memory compaction . 所以, 这个值设置接近1000, 说明系统在内存碎片的处理倾向于把旧的页换出, 以符合申请的需要; 而设置接近0, 表示系统在内存碎片的处理倾向于做memory compaction.
vm.hugepages_treat_as_movable = 0
    //控制是否可以从ZONE_MOVABLE内存域中分配大页面,ZONE_MOVABLE内存域只有在指定了kernelcore启动参数的情况下才会创建,如果没有指定kernelcore启动参数,hugepages_treat_as_movable参数则没有效果,通常并不会开启此参数。
vm.hugetlb_shm_group = 0
    //指定允许使用大页内存的用户,值为用户组id。比如如果mysql的innodb buffer pool要使用大页内存,那么就应该把mysql进程的用户的group id加上去。
vm.laptop_mode = 0
    //笔记本模式下,内核更智能的使用 I/O 系统,它会尽量使磁盘处于低能耗的状态下
vm.legacy_va_layout = 0
    //该文件表示是否使用最新的32位共享内存mmap()系统调用,Linux支持的共享内存分配方式包括mmap(),Posix,System VIPC。0,使用最新32位mmap()系统调用。1,使用2.4内核提供的系统调用。
vm.lowmem_reserve_ratio = 256 256 32
    //保留的lowmem,3列分别为DMA/DMA32/HighMem。lowmem_reserve_ratio是在各个zone之间进行一定的防卫预留,主要是防止高端zone在没内存的情况下过度使用低端zone的内存资源。具体看https://blog.csdn.net/joyeu/article/details/20063429
vm.max_map_count = 65536
    //进程中内存映射区域的最大数量。在调用malloc,直接调用mmap和mprotect和加载共享库时会产生内存映射区域。虽然大多数程序需要的内存映射区域不超过1000个,但是特定的程序,特别是malloc调试器,可能需要很多,例如每次分配都会产生一到两个内存映射区域。默认值是65536。
vm.memory_failure_early_kill = 0
    //控制在某个内核无法处理的内存错误发生的时候,如何去杀掉这个进程。当这些页有swap镜像的时候,内核会很好的处理这个错误,不会影响任何应用程序,但是如果没有的话,内核会把进程杀掉,避免内存错误的扩大.为1的时候,在发现内存错误的时候,就会把所有拥有内存错误的进程都杀掉.为0的时候,只是对这部分页进行unmap,然后把第一个试图进入这个页的进程杀掉
vm.memory_failure_recovery = 1
    //是否开启内存错误恢复机制.为1的时候,开启.为0的时候,一旦出现内存错误,就panic.

vm.min_free_kbytes = 67584    //这个参数用来指定强制Linux VM保留的空闲内存的最小值,单位是kb.它的主要用途是计算影响内存回收的三个参数 watermark[min/low/high].
1) watermark[high] > watermark [low] > watermark[min],各个zone各一套
2)在系统空闲内存低于 watermark[low]时,开始启动内核线程kswapd进行内存回收(每个zone一个),直到该zone的空闲内存数量达到watermark[high]后停止回收。如果上层申请内存的速度太快,导致空闲内存降至watermark[min]后,内核就会进行direct reclaim(直接回收),即直接在应用程序的进程上下文中进行回收,再用回收上来的空闲页满足内存申请,因此实际会阻塞应用程序,带来一定的响应延迟,而且可能会触发系统OOM。这是因为watermark[min]以下的内存属于系统的自留内存,用以满足特殊使用,所以不会给用户态的普通申请来用。
3)三个watermark的计算方法:
watermark[min] = min_free_kbytes换算为page单位即可,假设为min_free_pages。(因为是每个zone各有一套watermark参数,实际计算效果是根据各个zone大小所占内存总大小的比例,而算出来的per zone min_free_pages)
watermark[low] = watermark[min] * 5 / 4
watermark[high] = watermark[min] * 3 / 2
所以中间的buffer量为 high - low = low - min = per_zone_min_free_pages * 1/4。因为min_free_kbytes = 4* sqrt(lowmem_kbytes),也可以看出中间的buffer量也是跟内存的增长速度成开方关系。
4)可以通过/proc/zoneinfo查看每个zone的watermark
min_free_kbytes大小的影响
min_free_kbytes设的越大,watermark的线越高,同时三个线之间的buffer量也相应会增加。这意味着会较早的启动kswapd进行回收,且会回收上来较多的内存(直至watermark[high]才会停止),这会使得系统预留过多的空闲内存,从而在一定程度上降低了应用程序可使用的内存量。极端情况下设置min_free_kbytes接近内存大小时,留给应用程序的内存就会太少而可能会频繁地导致OOM的发生。
min_free_kbytes设的过小,则会导致系统预留内存过小。kswapd回收的过程中也会有少量的内存分配行为(会设上PF_MEMALLOC)标志,这个标志会允许kswapd使用预留内存;另外一种情况是被OOM选中杀死的进程在退出过程中,如果需要申请内存也可以使用预留部分。这两种情况下让他们使用预留内存可以避免系统进入deadlock状态。

vm.min_slab_ratio = 5     //只在numa架构上使用,如果一个内存域中可以回收的slab页面所占的百分比(应该是相对于当前内存域的所有页面)超过min_slab_ratio,在回收区的slabs会被回收。这样可以确保即使在很少执行全局回收的NUMA系统中,slab的增长也是可控的。
vm.min_unmapped_ratio = 1
    //只有在当前内存域中处于zone_reclaim_mode允许回收状态的内存页所占的百分比超过min_unmapped_ratio时,内存域才会执行回收操作。
vm.mmap_min_addr = 65536
    //指定用户进程通过mmap可使用的最小虚拟内存地址,以避免其在低地址空间产生映射导致安全问题;如果非0,则不允许mmap到NULL页,而此功能可在出现NULL指针时调试Kernel;mmap用于将文件映射至内存;该设置意味着禁止用户进程访问low 4k地址空间
vm.nr_hugepages = 0
    //指定系统中常驻大页内存的数量
vm.nr_hugepages_mempolicy = 0
    //proc/sys/vm/nr_hugepages接口会按照当前修改nr_hugepages的进程的NUMA策略进行HugePages分配,当然,默认情况下就是系统当前所有在线NUMA节点平均分配这些HugePages,除非那个NUMA节点本身没有足够的可用连续内存来生成HugePages,那么此时HugePages将由另外一个NUMA节点生成。通过/proc/sys/vm/nr_hugepages_mempolicy接口,可以指定HugePages页面具体由哪个NUMA节点生成。比如如果之前大页数量为0,那么执行numactl -m 0 echo 40 >/proc/sys/vm/nr_hugepages_mempolicy将会在node0上面创建40个大页,然后执行numactl -m 1 echo 60 >/proc/sys/vm/nr_hugepages_mempolicy将在node1上面创建20(60-40)个大页。
vm.nr_overcommit_hugepages = 0
    //表示程序申请HugePages可超过常驻HugePages数目的最大数目.也就是说如果申请的大页内存数量大于nr_hugepages+nr_overcommit_hugepages之和,那么会提示申请失败。具体看https://blog.csdn.net/cybertan/article/details/9035727
vm.nr_pdflush_threads = 0
    //指定pdflush线程的个数,由于在3.2之后的内核版本里,内存回写已经由pdflush改为writeback,因为该参数从此已经失效。
vm.numa_zonelist_order = default
    //指定zone排列的方式
vm.oom_dump_tasks = 1
    //当oom killer被引发的时候,将进程的信息输出,包括pid、uid、tgid、vm、rss、cpu等 默认为1
vm.oom_kill_allocating_task = 0
    //决定在oom的时候,oom killer杀哪些东西。 非0的时候,它会扫描进程队列,然后将可能导致内存溢出的进程杀掉,也就是占用内存最大的那个,但是设置为0的时候,它只杀掉导致oom的那个进程,避免了进程队列的扫描,但是释放的内存大小有限
vm.overcommit_kbytes = 0
vm.overcommit_memory = 0

vm.overcommit_ratio = 50
overcommit的标准有两个途径来设定,一种是直接定义overcommit_kbytes,这时候标准值是overcommit_kbytes+total_swap_pages.  另外一个标准(在overcommit_kbytes设定为0的时候使用)是和系统可以使用的page frame相关。并不是系统中的物理内存有多少,totalram_pages就有多少,实际上很多的page是不能使用的,例如linux kernel本身的正文段,数据段等就不能计入totalram_pages,还有一些系统reserve的page也不算数,最终totalram_pages实际上就是系统可以管理分配的总内存数目。overcommit_ratio是一个百分比的数字,50表示可以使用50%的totalram_pages,当然还有考虑total_swap_pages的数目,上文已经描述。
overcommit_memory这个参数就是用来控制内核对overcommit的策略。该参数可以设定的值包括:
#define OVERCOMMIT_GUESS        0 
#define OVERCOMMIT_ALWAYS        1 
#define OVERCOMMIT_NEVER        2
OVERCOMMIT_ALWAYS总是允许overcommit。OVERCOMMIT_NEVER是永远不要overcommit。OVERCOMMIT_GUESS的策略表示看情况而定。
vm.page-cluster = 3    //用来控制从swap空间换入数据的时候,一次连续读取的页数,这相当于对交换空间的预读。这里的连续是指在swap空间上的连续,而不是在内存地址上的连续。因为swap空间一般是在硬盘上,对硬盘设备的连续读取将减少磁头的寻址,提高读取效率。这个文件中设置的值是2的指数。就是说,如果设置为0,预读的swap页数是2的0次方,等于1页。如果设置为3,就是2的3次方,等于8页。同时,设置为0也意味着关闭预读功能。
vm.panic_on_oom = 0    //oom的时候是否内核直接panic
vm.percpu_pagelist_fraction = 0    //没看懂什么意思
vm.stat_interval = 1    //VM信息更新频率,默认每1秒更新一次
vm.swappiness = 60    //表示操作系统使用swap分区的倾向。swappiness=0的时候表示最大限度使用物理内存,然后才是 swap空间,swappiness=100的时候表示积极的使用swap分区,并且把内存上的数据及时的搬运到swap空间里面。linux的基本默认设置为60。也就是说,你的内存在使用到100-60=40%的时候,就开始出现有交换分区的使用。要想尽量使用物理内存,避免过早的使用swap分区,可以将该参数调小。
vm.user_reserve_kbytes = 131072    //和vm.admin_reserve_kbytes类似,只不过是针对普通用户的。
vm.vfs_cache_pressure = 100    //表示内核回收用于directory和inode cache内存(二者都属于slab)的倾向. 缺省值100表示内核将根据pagecache和swapcache,把directory和inode cache保持在一个合理的百分比;降低该值低于100,将导致内核倾向于保留directory和inode cache,当设置为0时,内核永远不会回收directory和inode cache,这将很容易导致内存溢出;增加该值超过100,将导致内核倾向于回收directory和inode cache。
vm.zone_reclaim_mode = 0    //
在申请内存时(内核的get_page_from_freelist()方法中),内核在当前zone内没有足够内存可用的情况下,会根据zone_reclaim_mode的设置来决策是从下一个zone找空闲内存还是在zone内部进行回收。这个值为0时表示可以从下一个zone找可用内存,非0表示在本地回收。这个文件可以设置的值及其含义如下:
echo 0 > /proc/sys/vm/zone_reclaim_mode:意味着关闭zone_reclaim模式,可以从其他zone或NUMA节点回收内存。
echo 1 > /proc/sys/vm/zone_reclaim_mode:表示打开zone_reclaim模式,这样内存回收只会发生在本地节点内。
echo 2 > /proc/sys/vm/zone_reclaim_mode:在本地回收内存时,可以将cache中的脏数据写回硬盘,以回收内存。
echo 4 > /proc/sys/vm/zone_reclaim_mode:可以用swap方式回收内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值