明天有朋友说系统显存不够了,想申请扩容,我free了一下,显存不还是绰绰有余吗?他回了一句,那种free不是只剩1G不到了嘛。嗯,确实这么,并且系统实际可用的显存,应当是下边的那种+buffers/cache,还有10G左右的空间。其实若果是新版本的free命令的话,显示结果会更友好一点。朋友没有去考量,尽管计算机的问题都经不起问为何,不过linux内核内存分配linux内核内存分配,此次,我想往里走一点,瞧瞧显存究竟是如何工作的?
(旧版)
(新版)
显存映射
我们常说的显存指的是化学显存,但数学显存只有内核才可以访问,这么进程怎么访问呢?Linux内核会给每位进程都提供了一个独立的虚拟地址空间,这就是我们常说的虚拟显存。虚拟地址空间的内部又被分为内核空间和用户空间两部份,不同字长的处理器,空间范围也不同。进程也有用户态和内核态,用户态的只能访问用户空间,切换到内核态才可以访问内核空间显存。其实,并不是所有的虚拟空间就会分配化学显存,按需分配,这些分配的方法是通过显存映射来管理的。内核为每位进程都维护了一张页表,拿来记录映射关系。当进程访问的虚拟地址在页表中查不到时,系统会形成一个缺页异常,步入内核空间分配化学显存、更新进程页表,最后再返回用户空间,恢复进程的运行。
显存映射的最小单位是页,一般为4KB,linux提供了多级页表和大页的机制来解决页表过大的问题。多级页表就是把显存分成区块来管理,将原先的映射关系改成区块索引和区块内的偏斜。大页就是比普通页更大的显存块,常见的大小有2MB和1GB。在页表的映射下,进程就可以通过虚拟地址来访问数学显存了。
虚拟显存空间分布
操作系统为了解决I/O底层的差别,创建了VFS(虚拟文件系统),为了解决I/O层与显存之间的差别,形成了虚拟显存。为了解决cpu与显存之间的差别,创建了进程。每位程序运行上去就会拥有一个自己的虚拟地址空间,32位cpu的操作系统,其地址线也为32位,所以虚拟地址空间为2^32-1=4G。虚拟显存最上方是内核空间,下方是用户空间,用户空间又分为多段。从高到低依次为:栈,文件映射段,堆,数据段,只读段。更详尽的界定去网上搜吧。可以通过proc的maps查看具体分布。
显存分配与回收
malloc()是C标准库提供的显存分配函数,对应到系统调用上,有两种实现方法linux系统官网,即brk()和mmap()。
对小块显存(大于128K),C标准库使用brk()来分配,也就是通过联通堆顶的位置来分配显存。这种显存释放后并不会立即归还系统,而是被缓存上去,这样就可以重复使用。可以降低缺页异常,提升显存访问率,但频繁的访问会导致显存碎片。
而大块显存(小于128K),则直接使用显存映射mmap()来分配,也就是在文件映射段找一块空闲显存分配出去。用完会立即归还系统,忙碌会导致大量的缺页异常,使内核的管理负担变大。
在内核空间,Linux则通过slab分配器来管理比页还小的小显存对象。在应用程序用完显存后,还须要调用free()或unmap(),来释放那些不用的显存。
假如显存紧张,会通过一系列机制来回收显存,如LRU,swap,以及OOM。OOM有个om_adj,范围是[-17,15],数值越大,表示进程越容易被OOM杀害linux手机软件,可以改写proc使一些重要程序不会被OOM杀害。
echo-16>/proc/$(pidofmysqld)/oom_adj
查看显存使用
free
buff/cache是缓存和缓冲区的大小;
available是新进程可用显存的大小。available除了包含未使用显存,还包括了可回收的缓存,但并不是所有缓存都可以回收。
top
VIRT是进程虚拟显存的大小,只要是进程申请过的显存,虽然还没有真正分配化学显存,也会计算在内。
RES是常驻显存的大小,也就是进程实际使用的数学显存大小,但不包括Swap和共享显存。
SHR是共享显存的大小,例如与其他进程共同使用的共享显存、加载的动态链接库以及程序的代码段等。
%MEM是进程使用化学显存占系统总显存的比率。
正题:MySQL啃不动了,先换换口味吧,快春节了,明天下班少了一大波人,办公室冷清的很。只要系统别挂,我应当也能摸几天鱼了,近来处在疲累期,动力不是很大,嗯。。。准备写个年终总结,看心情吧。
参考资料:倪朋飞,Linux性能优化实战