本文章结合自csdn(whatday)/挖站否
什么是linux的内存机制?
我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概念。
物理内存就是系统硬件提供的内存大小,是真正的内存,相对于物理内存,在linux下还有一个虚拟内存的概念,虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space)。
作为物理内存的扩展,linux会在物理内存不足时,使用交换分区的虚拟内存,更详细的说,就是内核会将暂时不用的内存块信息写到交换空间,这样以来,物理内存得到了释放,这块内存就可以用于其它目的,当需要用到原始的内容时,这些信息会被重新从交换空间读入物理内存。
Linux的内存管理采取的是分页存取机制,为了保证物理内存能得到充分的利用,内核会在适当的时候将物理内存中不经常使用的数据块自动交换到虚拟内存中,而将经常使用的信息保留到物理内存。
要深入了解linux内存运行机制,需要知道下面提到的几个方面:
-
Linux系统会不时的进行页面交换操作,以保持尽可能多的空闲物理内存,即使并没有什么事情需要内存,Linux也会交换出暂时不用的内存页面。这可以避免等待交换所需的时间。
-
Linux 进行页面交换是有条件的,不是所有页面在不用时都交换到虚拟内存,linux内核根据”最近最经常使用“算法,仅仅将一些不经常使用的页面文件交换到虚拟 内存,有时我们会看到这么一个现象:linux物理内存还有很多,但是交换空间也使用了很多。其实,这并不奇怪,例如,一个占用很大内存的进程运行时,需 要耗费很多内存资源,此时就会有一些不常用页面文件被交换到虚拟内存中,但后来这个占用很多内存资源的进程结束并释放了很多内存时,刚才被交换出去的页面 文件并不会自动的交换进物理内存,除非有这个必要,那么此刻系统物理内存就会空闲很多,同时交换空间也在被使用,就出现了刚才所说的现象了。关于这点,不 用担心什么,只要知道是怎么一回事就可以了。
-
交换空间的页面在使用时会首先被交换到物理内存,如果此时没有足够的物理内存来容纳这些页 面,它们又会被马上交换出去,如此以来,虚拟内存中可能没有足够空间来存储这些交换页面,最终会导致linux出现假死机、服务异常等问题,linux虽 然可以在一段时间内自行恢复,但是恢复后的系统已经基本不可用了。
因此,合理规划和设计Linux内存的使用,是非常重要的.
1、 swap到底是干嘛的?
我们一般所说的swap,指的是一个交换分区或文件。在Linux上可以使用swapon -s命令查看当前系统上正在使用的交换空间有哪些,以及相关信息:
[zorro@zorrozou-pc0 linux-4.4]$ swapon -s
Filename Type Size Used Priority
/dev/dm-4 partition 33554428 0 -1
从功能上讲,交换分区主要是在内存不够用的时候,将部分内存上的数据交换到swap空间上,以便让系统不会因内存不够用而导致oom或者更致命的情况出现。
所以,当内存使用存在压力,开始触发内存回收的行为时,就可能会使用swap空间。
2、 swappiness到底是用来调节什么的?
很多人应该都知道 /proc/sys/vm/swappiness 这个文件,是个可以用来调整跟swap相关的参数。这个文件的默认值是60,可以的取值范围是0-100。
这很容易给大家一个暗示:我是个百分比哦!
那么这个文件具体到底代表什么意思呢?我们先来看一下说明:
======
swappiness
This control is used to define how aggressive the kernel will swap memory pages. Higher values will increase agressiveness, lower values decrease the amount of swap.
A value of 0 instructs the kernel not to initiate swap until the amount of free and file-backed pages is less than the high water mark in a zone.
The default value is 60.
======
这个文件的值用来定义内核使用swap的积极程度:
-
值越高,内核就会越积极的使用swap;
-
值越低,就会降低对swap的使用积极性。
-
如果这个值为0,那么内存在free和file-backed使用的页面总量小于高水位标记(high water mark)之前,不会发生交换。
在这里我们可以理解file-backed这个词的含义了,实际上就是上文所说的文件映射页的大小。
3、 kswapd什么时候会进行swap操作?
我们回到kswapd周期检查和直接内存回收的两种内存回收机制。
直接内存回收比较好理解,当申请的内存大于剩余内存的时候,就会触发直接回收。
那么kswapd进程在周期检查的时候触发回收的条件是什么呢?
还是从设计角度来看,kswapd进程要周期对内存进行检测,达到一定阈值的时候开始进行内存回收。
这个所谓的阈值可以理解为内存目前的使用压力,就是说,虽然我们还有剩余内存,但是当剩余内存比较小的时候,就是内存压力较大的时候,就应该开始试图回收些内存了,这样才能保证系统尽可能的有足够的内存给突发的内存申请所使用。
4、 什么是内存水位标记?
那么如何描述内存使用的压力呢?
Linux内核使用水位标记(watermark)的概念来描述这个压力情况。
Linux为内存的使用设置了三种内存水位标记:high、low、min。他们 所标记的含义分别为:
剩余内存在high以上表示内存剩余较多,目前内存使用压力不大;
high-low的范围表示目前剩余内存存在一定压力;
low-min表示内存开始有较大使用压力,剩余内存不多了;
min是最小的水位标记,当剩余内存达到这个状态时,就说明内存面临很大压力。
小于min这部分内存,内核是保留给特定情况下使用的,一般不会分配。
内存回收行为就是基于剩余内存的水位标记进行决策的:
当系统剩余内存低于watermark[low]的时候,内核的kswapd开始起作用,进行内存回收。直到剩余内存达到watermark[high]的时候停止。
如果内存消耗导致剩余内存达到了或超过了watermark[min]时,就会触发直接回收(direct reclaim)。
明白了水位标记的概念之后,zonefile + zonefree <= high_wmark_pages(zone)这个公式就能理解了。
这里的zonefile相当于内存中文件映射的总量,zonefree相当于剩余内存的总量。
内核一般认为,如果zonefile还有的话,就可以尽量通过清空文件缓存获得部分内存,而不必只使用swap方式对anon的内存进行交换。
整个判断的概念是说,在全局回收的状态下(有global_reclaim(sc)标记),如果当前的文件映射内存总量+剩余内存总量的值评估小于等于watermark[high]标记的时候,就可以进行直接swap了。
5、 swap分区的优先级(priority)有啥用?
在使用多个swap分区或者文件的时候,还有一个优先级的概念(Priority)。
在swapon的时候,我们可以使用-p参数指定相关swap空间的优先级, 值越大优先级越高 ,可以指定的数字范围是-1到32767。
内核在使用swap空间的时候总是先使用优先级高的空间,后使用优先级低的。
当然如果把多个swap空间的优先级设置成一样的,那么两个swap空间将会以轮询方式并行进行使用。
如果两个swap放在两个不同的硬盘上,相同的优先级可以起到类似RAID0的效果,增大swap的读写效率。
另外,编程时使用mlock()也可以将指定的内存标记为不会换出,具体帮助可以参考man 2 mlock。
实际操作:
一、VPS设置swap空间
1.1 swap要多大?
综合网上的相关资料,一般来说2GB的内存的VPS至少要2GB的Swap空间, 相关的参考如下:
物理内存 交换分区(SWAP)
<= 4G 至少4G
4~16G 至少8G
16G~64G 至少16G
64G~256G 至少32G
1.2 创建swap分区
Linux VPS主机设置swap空间的基本命令如下:
#查看swap分区的大小
free -h
#删除所有SWAP分区
swapoff -a
#创建swap分区的文件,其中bs是每块的大小,count是块的数量,bs*count,就是swap文件的大小了,这里就是1M*2048=2G
dd if=/dev/zero of=/root/swapfile bs=1M count=2048
#格式化交换分区文件:
mkswap /root/swapfile
#启用swap分区文件:
swapon /root/swapfile
#添加开机启动,修改 /etc/fstab 这个文件,添加或者修改这一行:
/root/swapfile swap swap defaults 0 0 #适用于redhat或centos系统
/root/swapfile none swap sw 0 0 #适用于Ubuntu系统
#或者直接执行以下命令写入/etc/fstab
echo "/root/swapfile swap swap defaults 0 0" >>/etc/fstab #适用于redhat或centos系统
echo "/root/swapfile none swap sw 0 0" >>/etc/fstab #适用于Ubuntu系统
二、Linux真实使用内存
Linux的内存管理机制与Windows有所不同,linux系统中,是进程优先使用内存,而不是磁盘,这样会加快读取速度。当有新的进程启动时,再从内存中开辟出一定空间,为新的进程所用。即使进程退出,也不会立刻从内存中清理掉,这样可以加快下次启动进程的速度,所以内存一直是使用率很高的。那么如何查看Linux真实使用内存?
2.1 命令查看
执行命令:free -h可以查看Linux VPS主机的内存使用情况:
root@localhost:~# free -h
total used free shared buff/cache available
Mem: 2.0G 1.3G 382M 106M 280M 416M
Swap: 2.7G 146M 2.5G
Linux VPS主机真实内存占用到底是多少呢?用 free 指令查看一下输出,用 used 减去 buffer 和 cache,才是你运行中的程序所占用的空间。
如上面的例子:使用了4G的内存,3.7G被占用,但是buuffer和cached部分作为缓存,可以使用命中率的方式提高使用效率,而且这部分缓存是根据指令随时可以释放的,我们可以认为这部分内存没有实际被使用,也可以认为它是空闲的,即真实内存=1.3G-0.28G
因此查看目前进程正在实际被使用的内存,是used-(buffers+cache),也可以认为如果swap没有大量使用,mem还是够用的,只有mem被当前进程实际占用完(没有了buffers和cache),才会使用到swap的。
三、Linux内存分配控制
3.1 swappiness参数
swappiness是Linux的一个内核参数,控制系统在进行swap时,内存使用的相对权重。swappiness参数值可设置范围在0到100之间。 此参数值越低,就会让Linux系统尽量少用swap分区,多用内存;参数值越高就是反过来,使内核更多的去使用swap空间。
Ubuntu系统swappiness默认值为60,表示的含义可以这样来理解,当剩余物理内存低于40%(40=100-60)时,开始使用swap分区。CentOS系统此参数的默认值是30。设置为100可能会影响整体性能,如果内存充足,就可以将这个值设置很低,甚至为0,以避免系统进行swap而影响性能。
3.2 swappiness=0 ?
我们都知道,Linux的进程使用的内存分为2种:
-
1.file-backed pages(有文件背景的页面,比如代码段、比如read/write方法读写的文件、比如mmap读写的文件,它们有对应的硬盘文件,因此如果要交换,可以直接和硬盘对应的文件进行交换;比如读取一个文件,没有关闭,也没有修改,交换时,就可以将这个文件直接放回硬盘,代码处理其实就是删除这部分内容,只保留一个索引,让系统知道这个文件还处于打开状态,只是它的内容不在内存,还在硬盘上),此部分页面叫做page cache;
-
2.anonymous pages(匿名页,如stack,heap,CoW后的数据段等;他们没有对应的硬盘文件,因此如果要交换,只能交换到swap分区),此部分页面,如果系统内存不充分,可以被swap到swapfile或者硬盘的swap分区。
因此,Linux在进行内存回收(memory reclaim)的时候,实际上可以从1类和2类这两种页面里面进行回收,而swappiness值就决定了回收这2类页面的优先级。swappiness越大,越倾向于回收匿名页;swappiness越小,越倾向于回收file-backed的页面。当然,它们的回收方法都是一样的LRU算法。
在Linux的早期版本(2012年以前的版本,kernel 3.5-rc1),哪怕swappiness被设置为0,其实匿名页仍然有被交换出去的机会。2012年开始,这个细节有了变化。https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fe35004fbf9eaf67482b074a2e032abb9c89b1dd
swappiness参数内存控制
如果swappiness=0,除非系统的内存过小(nr_free + nr_filebacked < high watermark)这种恶劣情况发生,都只是考虑交换file-backed的pages,就不会考虑交换匿名页了。
swappiness参数内存占用
于是现在的swappiness如果等于0的话,意味着哪怕匿名页占据的内存很大,哪怕swap分区还有很多的剩余空间,除非恶劣情况发生,都不会交换匿名页,因此这可能造成更大的OOM(Out Of Memory)压力。不像以前,平时会一直兼顾着回收page cache和匿名页。所以,现在如果想将swappiness设置为0,那是要好好想想的了。
3.3 swappiness设置
如何查看系统当前的swappiness值?命令如下(数值为60,表示你的内存在使用到100-60=40%的时候,就开始出现有Swap交换分区的使用):
cat /proc/sys/vm/swappiness
#60
如何配置swappiness值?使用以下命令可以设置swappiness值:
#临时性修改:
sudo sysctl vm.swappiness=10
#永久性修改:
#在/etc/sysctl.conf 文件里添加如下参数:
vm.swappiness=10
#然后重启系统
四、总结
swap到底怎么用?
要还是不要?
设置大还是小?
相关参数应该如何配置?
是要根据我们自己的生产环境的情况而定的。
阅读完本文后希望大家可以明白一些swap的深层次知识。
Q&A:
-
一个内存剩余还比较大的系统中,是否有可能使用swap?
A: 有可能,如果运行中的某个阶段出发了这个条件”zonefile+zonefree<=high_wmark_pages(zone) “,就可能会swap。
-
swappiness设置为0就相当于关闭swap么?
A: 不是的,关闭swap要使用swapoff命令。swappiness只是在内存发生回收操作的时候用来平衡cache回收和swap交换的一个参数,调整为0意味着,尽量通过清缓存来回收内存。
-
A: swappiness设置为100代表系统会尽量少用剩余内存而多使用swap么?
不是的,这个值设置为100表示内存发生回收时,从cache回收内存和swap交换的优先级一样。就是说,如果目前需求100M内存,那么较大机率会从cache中清除50M内存,再将匿名页换出50M,把回收到的内存给应用程序使用。但是这还要看cache中是否能有空间,以及swap是否可以交换50m。内核只是试图对它们平衡一些而已。
-
kswapd进程什么时候开始内存回收?
A: kswapd根据内存水位标记决定是否开始回收内存,如果标记达到low就开始回收,回收到剩余内存达到high标记为止。
-
如何查看当前系统的内存水位标记?
A: cat /proc/zoneinfo。
对于Linux,无论是多大内存,还是要设立Swap交换分区,这样特别有利于在内存耗尽时及时启用Swap空间。我们经常看到Linux的内存占用达到90%以上,这是因为Linux的内存管理机制与Windows有所不同,实际使用内存还是比较小的。
一般来说swappiness设置在10-20之间,这个需要根据你自己的网站的业务需要。例如想要尽量保持稳定的话,可以把swappiness的数值调高,想要加快读取速度可以把swappiness设置得低一些,不建议把swappiness设置为0,容易造成进程崩溃。
.