Linux 内存管理 页回收和swap机制

页高速缓存和页写回机制


页是物理内存或虚拟内存中一组连续的线性地址,Linux内核以页为单位处理内存,页的大小通常是4KB。当一个进程请求一定量的页面时,如果有可用的页面,内核会直接把这些页面分配给这个进程,否则,内核会从其它进程或者页缓存中拿来一部分给这个进程用。内核知道有多少页可用,也知道它们的位置。

如果在进程请求指定的内存页时,没有可用的内存页,那么这个时候内核就会去尝试释放特定的内存页给新的请求去使用,这个过程就叫做内存回收。其中有个进程叫做kswap内核线程,它就是负责页面的回收的。

kswapd内核线程负责页面回收。它是虚拟内存管理中负责换页的,操作系统每过一定时间就会唤醒kswapd ,它基于最近最少使用原则(LRU,Least Recently Used)在活动页中寻找可回收的页面,看看内存是否紧张,如果不紧张,则睡眠,在kswapd中,有2个阀值,pages_high和 pages_low,当空闲内存页的数量低于pages_low的时候,kswapd进程就会扫描内存并且每次释放出32个free pages,直到free page的数量到达pages_high。

在负载比较大的时候,内存使用很紧张的时候,一般会看到两个进程,kswap0 kswap1, 如果这两个进程占用的资源比较多,尤其在负载比较大的业务系统当中,可能会引起系统宕机。这个时候就要去优化系统,增加硬件。

[root@master ~]# ps -aux | grep kswap
root         30  0.0  0.0      0     0 ?        S    08:13   0:01 [kswapd0]

kswapd内核线程被频繁的唤醒,他就会过度的消耗cpu。

 

 

内核线程kswapd0用来定期回收内存


话说回来,既然 Swap 是为了回收内存,那么 Linux 到底在什么时候需要回收内存呢?前面一直在说内存资源紧张,又该怎么来衡量内存是不是紧张呢? 

一个最容易想到的场景就是,有新的大块内存分配请求,但是剩余内存不足。这个时候系统就需要回收一部分内存(比如前面提到的缓存),进而尽可能地满足新内存请求。这个过程通常被称为直接内存回收。

除了直接内存回收,还有一个专门的内核线程用来定期回收内存,也就是 kswapd0。

为了衡量内存的使用情况,kswapd0 定义了三个内存阈值(watermark,也称为水位),分别是页最小阈值(pages_min)、页低阈值(pages_low)和页高阈值(pages_high)。剩余内存,则使用 pages_free 表示。 

[root@docker ~]# ps -ef | grep kswapd0
root        48     2  0 09:58 ?        00:00:00 [kswapd0]

这里,我画了一张图表示它们的关系。 

kswapd0 定期扫描内存的使用情况,并根据剩余内存落在这三个阈值的空间位置,进行内存的回收操作。 

  • 剩余内存小于页最小阈值,说明进程可用内存都耗尽了,只有内核才可以分配内存。
  • 剩余内存落在页最小阈值和页低阈值中间,说明内存压力比较大,剩余内存不多了。这时 kswapd0 会执行内存回收,直到剩余内存大于高阈值为止。
  • 剩余内存落在页低阈值和页高阈值中间,说明内存有一定压力,但还可以满足新内存请求
  • 剩余内存大于页高阈值,说明剩余内存比较多,没有内存压力。 

我们可以看到,一旦剩余内存小于页低阈值,就会触发内存的回收。页最小阈值,其实可以通过内核选项 /proc/sys/vm/min_free_kbytes 来间接设置。min_free_kbytes 设置了页最小阈值,而其他两个阈值,都是根据页最小阈值计算生成的,计算方法如下 :

[root@docker ~]# cat /proc/sys/vm/min_free_kbytes 
67584
pages_low = pages_min*5/4
pages_high = pages_min*3/2

 

 

swap交换空间


为了在多进程的环境下,使用内存地址相互不受影响,相互隔离,于是操作系统就为进程独立的分配了虚拟地址空间,每个进程关心自己的虚拟地址就行了。

作为基础也不需要关心物理地址的事情,每个进程都有自己的虚拟空间,而物理内存只有一个,当启动了大量的进程,物理内存就会非常非常的紧张,于是就可以通过内存交换技术,把不经常使用的内存暂时放到硬盘上这个叫做换出。需要的时候从硬盘加载到内存,这就叫做换入。 

swap交换空间 swap字面意思是交换,它是磁盘上的一块区域,可以是一个分区,也可以是一个文件,或者是他们的组合。简单点说,当系统物理内存吃紧时,Linux会将内存中不常访问的数据保存到swap上,这样系统就有更多的物理内存为各个进程服务,而当系统需要访问swap上存储的内容时,再将swap上的数据加载到内存中,这就是我们常说的swap out和swap in。 

当物理内存当中有不经常访问的数据,会从物理内存转到交换空间里面来,程序访问的时候依然是通过地址映射关系。

Linux内核根据最近,最经常使用的算法,将一些不经常使用的页面文件交换到swap里面来。

有时候可以看到物理内存还有很多,但swap也使用了很多,这很正常,一个占用很大内存进程运行的时候需要占用很大的内存资源,此时就有不常用的页面交换到swap里面,当占用很多内存的进程结束了,就会释放很多的内存,交换出去的页面文件并不会再自动的交换进物理内存里面,触发有必要,这个时候就可以看到系统的物理内存的空闲有很多,但是swap也被使用,这样就出现了物理内存有很多,但是虚拟内存也使用了很多的情况。

swap是存放在磁盘上的,磁盘的速度和内存比较起来慢了好几个数量级,如果不停的读写swap,那么对系统的性能肯定有影响,尤其是当系统内存很吃紧的时候,读写swap空间发生的频率会很高,导致系统运行很慢,像死机一样,这个时候添加物理内存是唯一的解决办法。

对于大型的应用程序来说,在启动的时候会使用大量的内存,在很多情况下这些内存只是在启动的时候用一下,后面在运行的时候很少使用这部分的内存,有了swap之后就可以将这部分不经常使用的内存数据保存到swap上面去,从而释放出更多的物理内存供系统去使用。

很多Linux发行版本,比如乌班图,它的休眠机制就是依赖于swap分区的,当系统休眠的时候,会将内存当中数据保存到swap里面,等下次系统启动时候,将数据加载到内存里面,这样就可以加快系统的启动速度,如果要使用休眠功能的话必须要使用swap分区。

还有一种情况,物理内存有限,但是想运行耗内存的程序怎么办?这样需要配置足够的swap空间来达到这个目的,虽然慢一点,程序还是可以运行的。

大部分情况下物理内存都是够用的,但是总有一些意想不到的状态发生,比如某个进程需要的内存超过了预期,或者有些进程存在内存泄漏。 

在服务器上,开启swap,还是有很大用途的,虽然大部分情况下,物理内存都是够用的,但是总有一些意想不到的状况,比如某个进程需要的内存超过了预期,或者有进程存在内存泄漏等,当内存不够的时候,就会触发内核的OOM killer,根据OOM killer的配置,某些进程会被kill掉或者系统直接重启,不过有了swap后,可以拿swap当内存用,虽然速度慢了点,但至少给了我们一个去debug、kill进程或者保存当前工作进度的机会。

实际生产当中要不要配置swap,看情况。

内存不够用:物理内存明显不够用,但是又想跑程序,添加swap是唯一的选择。

内存勉强够用:建议配置swap,这样可以通过交换有更多的物理内存供系统使用。

内存非常充足:不需要休眠功能,并且内存足够多,swap其实没有什么作用,但是很难保证物理内存都是够用的,因为总有意想不到的情况发生,如上所说。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值