其他工程问题以及调优
- DMA和cache一致性
- 内存的cgroup
- memcg子系统分析
- 性能方面的调优: page in/out, swap in/out
- Dirty ratio的一些设置
- swappiness
DMA和cache一致性
工程中,DMA可以直接在内存和外设进行数据搬移,而CPU访问内存时要经过MMU。DMA访问不到CPU内部的cache,所以会出现cache不一致的问题。因为CPU读写内存时,如果在cache中命中,就不会再访问内存。
当CPU 写memory时,cache有两种算法:write_back ,write_through。一般都采用write_back。cache的硬件,使用LRU算法,把cache中的数据替换到磁盘。
cache一致性问题,主要靠以上两类api来解决这个问题。一致性DMA缓冲区api,和流式DMA映射api。CPU通过MMU访问DMA区域,在页表项中可以配置这片区域是否带cache。
现代的SoC,DMA引擎可以自动维护cache的同步。
内存的cgroup
进程分group,内存也分group。
进程调度时,把一组进程加到一个cgroup,控制这一组进程的CPU权重和最大CPU占用率。在/sys/fs/cgroup/memory创建一个目录,把进程放到这个group。可以限制某个group下的进程不用swap,每个group的swapiness都可以配置。
比如,当你把某个group下的swapiness设置为0,那么这个group下进程的匿名页就不允许交换了。
/proc/sys/vm/swapiness是控制全局的swap特性,不影响加到group中的进程。
也可以控制每个group的最大内存消耗为200M,当这个group下进程使用的内存达到200M,就oom。
demo: 演示用memory cgroup来限制进程group内存资源消耗的方法
1 | swapoff -a |
memory cgroup子系统分析
memcg v1的参数有25个, 通过数据结构 res_counter 来计算。
1 | ~~~ |
内存的使用量 mem_cgroup_usage 通过递归RSS和page cache之和来计算。
struct mem_cgroup是负责内存 cgroup 的结构
1 | struct mem_cgroup { |
这些参数的入口都在mm/memcontrol.c下,比如说memory.usage_in_bytes的读取调用的是mem_cgroup_read函数, 统计的入口是mem_cgroup_charge_common(),如果统计值超过限制就会在cgroup内进行回收。调用者分别是缺页时调用的mem_cgroup_newpage_charge和 page cache相关的mem_cgroup_cache_charge。
当进程进入缺页异常的时候就会分配具体的物理内存,当物理内存使用超过高水平线以后,换页daemon(kswapd)就会被唤醒用于把内存交换到交换空间以腾出内存,当内存恢复至高水平线以后换页daemon进入睡眠。
缺页异常的入口是 __do_fault,
RSS在page_fault的时候记录,page cache是插入到inode的radix-tree中才记录的。
RSS在完全unmap的时候减少计数,page cache的page在离开inode的radix-tree才减少计数。
即使RSS完全unmap,也就是被kswapd给换出,可能作为SwapCache存留在系统中,除非不作为SwapCache,不然还是会被计数。
一个换入的page不会马上计数,只有被map的时候才会,当进行换页的时候,会预读一些不属于当前进程的page,而不是通过page fault,所以不在换入的时候计数。
脏页写回的“时空”控制
“脏页”:当进程修改了高速缓存里的数据时,该页就被内核标记为脏页,内核将会在合适的时间把脏页的数据写到磁盘中去,以保持高速缓存中的数据和磁盘中的数据是一致的。
通过时间(dirty_expire_centisecs)和比例,控制Linux脏页返回。
dirty_expire_centisecs:当Linux中脏页的时间到达dirty_expire_centisecs,无论脏页的数量多少,必须立即写回。通过在后台启动进程,进行脏页写回。
默认时间设置为30s。
dirty_ratio,dirty_background_ratio 基于空间的脏页写回控制。
不能让内存中存在太多空间的脏页。如果一个进程在循环调用write,当达到dirty_background_ratio后,后台进程就开始写回脏页。默认值5%。当达到第2个阈值dirty_ratio时,应用进程被阻塞。当内存中的脏页在两个阈值之间时,应用程序是不会阻塞。
内存何时回收:水位控制
脏页写回不是 内存回收。
脏页写回:是保证在内存不在磁盘的数据不要太多。
水位控制:是指内存何时开始回收。
由/pro/sys/vm/min_free_kbytes 控制,根据内存大小算出来的平方根。
pf_mem_alloc,允许内存达到低水位以下,还可以继续申请。内存的回收,在最低水位以上就开始回收。
每个Zone都有自己的三个水位,最小的水位是根据min_free_kbytes控制。5/4min_free_kbytes =low 3/2min_free_kbytes =high ,
Zone的最小内存达到5/4的low 水位,Linux开始后台回收内存。直到达到6/4的high水位,开始不回收。
当Zone的最小内存达到min水位,应用程序的写会直接阻塞。
实时操作系统,
当你要开始回收内存时,回收比例通过swappiness越大,越倾向于回收匿名页;swappiness越小,越倾向于回收file-backed的页面。
当把cgroup中的swapiness设置为0,就不回收匿名页了。
当你的应用会经常去访问数据malloc的内存,需要把swapiness设置小。dirty的设置,水位的设置都没有一个标准,要看应用使用内存的情况而定。
getdelays工具:用来评估应用等待CPU,内存,IO,的时间。
linux/Documents/accounting
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASKSTATS=y
vmstat 可以展现给定时间间隔的服务器的状态值,包括Linux的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。
1 | vmstat 1 |
Documents/sysctl/vm.txt 中有所有参数最细节的描述。