在进程的执行过程中,Linux内核会根据需要给进程分配一块内存区域,进程就把这块区域作为工作区,按需求执行操作。内核会以更加动态的方式分配空间。系统上运行的进程成千上万,但内存是有限的。因此,Linux必须高效地处理内存资源。
物理内存就是系统硬件提供的内存大小,是真正的内存。在Linux下还有一个逻辑内存的概念,逻辑内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存区域,用作逻辑内存的磁盘空间被称为交换空间(Swap Space)。但是,在LInux操作系统中,无论是系统内核,还是应用程序都不能直接使用物理内存和逻辑内存,要使用这些内存,需要通过一个映射机制来实现。也就是说,Linux操作系统会把所有内存(包括物理内存和虚拟内存)都映射成虚拟内存,这样,应用程序在使用内存时,就需要向Linux内核申请一个特定大小的内存映射,并且收到一个虚拟内存的映射。这个申请到的虚拟内存不一定全部是物理内存的映射,还可能包含由磁盘上的交换空间映射来的内存。
Linux的这种虚拟内存管理机制对用户和应用程序通常时不可见的。所以,掌握内存调优的方法,就必须要理解内存架构、地址布局以及Linux如何高效管理内存空间。
页是物理内存或虚拟内存中一组连续的线性地址,Linux内核以页为单位处理内存,页的大小通常是4KB。当一个进程请求一定数量的页时,如果有可用的页,内核会直接把这些页分配给进程,否则,内核会从其他进程或者页缓存中拿来一部分给这个进程用。内核知道有多少页可用,也知道它们的位置。
如果进程请求指定数量的内存页时没有可用的内存页,内核会尝试释放特定的内存页给新的请求使用。这个过程叫作内存回收。其中,kswapd内核进程负责页面回收。
kswapd在虚拟内存管理页中负责换页,操作系统每过一段时间就会唤醒kswapd,它基于最近很少使用原则(Least Recently Used,LRU)在活动页中找可回收的页面,看看内存是否紧张,如果不紧张,则进入睡眠状态。在kswapd中有两个阈值(pages_high和pages_low),当空闲内存页数量低于pages_low的时候kswap进程就会扫描内存并且每次释放出32个free pages,直到free pages的数量达到pages_high。
Linux在负载比较大(内存紧张)的时候一般会看到这样两个进程:kswap0和kswap1。如果这些进程占用资源非常高,就要考据优化系统或添加硬件资源。
在某些情况下,kswapd进程如果被频繁唤醒会过度消耗CPU,此时可以通过设置大页内存(HugePages)来解决。
需要注意的,页面回收会丢弃缓存、丢弃Swap,这一定程度上会影响系统性能,而kswapd进程要做的是维护系统性能与页面分配的平衡。
Swap space是磁盘上的一块区域,可以是一个分区,也可以是一个文件,或者是他们的组合。Linux的内存管理采取的是分页存取机制,为了保证物理内存能得到充分的利用,内核会在适当的时候将物理内存中不经常使用的内存页面自动交换到Swap交换空间中,而将经常使用的信息保留到物理内存。简单点说,当系统物理内存吃紧时,Linux会将内存中不常访问的数据保存到Swap上,这样系统就有更多的物理内存为各个进程服务,而当系统需要访问swap上存储的内容时,再将swap上的数据加载到内存中。
虽然大部分情况下,物理内存都是够用的,但是总有一些意想不到的状况,比如某个进程需要的内存超过了预期,或者有进程存在内存泄漏等,当内存不够的时候,就会触发内核的OOM killer,某些进程会被kill掉或者系统直接重启。不过有了Swap后,可以拿swap当内存用,虽然速度慢了点,但至少给了我们一个去debug、kill进程或者保存当前工作进度的机会。
OOM Killer通过检查所有正在运行的进程并给它们分配一个不良分数,得分最高的进程会被终止。评分规则如下:
进程及其所有子进程都在使用大量内存。
为了释放足够的内存,需要终止(理想情况下是一个)最少数量的进程。
根进程、内核进程和重要系统进程的得分要低得多。
首先,Linux系统会不时地进行页面交换操作,以保持尽可能多的空闲物理内存,即使没有什么事情需要内存,Linux也会交换出暂时不用的内存页面。
其次,交换是有条件的,不是所有页面在不用时都交换到Swap。Linux内核根据“最近最少使用的”算法,仅仅将最近很少使用的页面文件交换到Swap。有时会看到一个现象:Linux物理内存还有很多,但是Swap却仍使用了很多。这时因为一个占用很大内存的进程在运行时,需要耗费很多内存资源,此时就会有一些不常用的页面文件被交换到Swap中。但后来这个占用很多内存资源的进程结束并释放了很多物理内存时,刚才被交换出去的页面文件并不会自动地交换进物理内存进行释放,除非有这个必要。那么此时就会出现系统物理内存空闲很多,但交换空间仍在被大量使用的现象。
查看/proc/sys/vm/swappiness,vm.swappiness=0表示禁用交换区,vm.swappiness=100表示尽最使用交换区。