为什么讨论"稳定性"就像信息一次只能出现在一个地方?
我一直在阅读Linux的" swappiness"可调参数,该参数可控制内核在不使用应用程序时将其内存交换到磁盘的积极程度。如果我们使用Google这个字眼,就会看到很多这样的页面,讨论正反两面。简而言之,该参数如下所示:
If your swappiness is too low, inactive applications will hog all the system memory that other programs might want to use. If your swappiness is too high, when you wake up those inactive applications, there's going to be a big delay as their state is read back off the disk.
这种说法对我来说毫无意义。如果我有一个不活动的应用程序正在使用大量内存,为什么内核不将其内存分页到磁盘并将该数据的另一个副本保留在内存中?这似乎是两全其美的:如果另一个应用程序需要该内存,则它可以立即声明物理RAM并开始对其进行写入,因为它的另一个副本在磁盘上,并且在非活动应用程序被唤醒时可以交换回去。向上。而且,当原始应用程序唤醒时,其仍在RAM中的任何页面都可以按原样使用,而不必将其从磁盘中拉出。
还是我错过了什么?
解决方案
即使将应用程序的内存分页到磁盘上并将其保留在内存中,我们仍然必须决定何时应将某个应用程序视为"非活动",而这正是交换性所控制的。就IO而言,分页到磁盘非常昂贵,并且我们不想经常这样做。这个方程式还有另一个变量,那就是Linux使用剩余的内存作为磁盘缓冲区/高速缓存的事实。
If I have an inactive application that's using a ton of memory, why doesn't the kernel page its memory to disk AND leave another copy of that data in-memory?
可以说我们做到了。我们将页面写入磁盘,但将其保留在内存中。过了一会儿,另一个进程需要内存,因此我们要从第一个进程中删除该页面。
我们需要绝对确定地知道自从页面被写到磁盘以来,第一个进程是否已经修改了页面。如果有的话,我们必须再次写出来。我们跟踪此问题的方法是,当我们第一次将其写到磁盘时,取消对该页面的进程写权限。如果该过程尝试再次写入该页面,将出现页面错误。内核可以注意到,在恢复写许可权并允许应用程序继续运行之前,该进程已弄脏了页面(因此将需要再次写出)。
问题就出在这里。从页面上剥夺写权限实际上有点昂贵,尤其是在多处理器计算机中。所有CPU清除其页面翻译的缓存以确保它们没有写许可权,这一点很重要。
如果该过程确实写入了页面,则发生页面错误的代价甚至更高。我以为这些页面中不平凡的部分最终将导致该错误,而将错误留在内存中会吞噬我们一直在寻找的收益。
那么值得吗?老实说我不知道。我只是在解释为什么将页面留在内存中听起来并不那么明显。
(*)整个过程与称为写时复制的机制非常相似,该机制在进程fork()s时使用。子进程很可能只执行几条指令并调用exec(),因此复制所有父页面是很愚蠢的。取而代之的是取消了写许可权,仅允许孩子运行。写时复制很成功,因为几乎不会发生页面错误:子代几乎总是立即调用exec()。
根据这个1,这正是Linux所做的。
我仍在努力理解其中的很多内容,因此,任何权威的链接都将不胜感激。
VM要做的第一件事是清除页面并将其移至清除列表。
清理匿名内存(没有实际文件后备存储的东西时,我们可以在/ proc // maps中看到匿名且后面没有文件系统vnode存储的段),VM要做的第一件事是取出"脏"页面并"清理",然后将页面内容写出来进行交换。现在,当虚拟机缺乏完全可用的内存,并且担心其授予新的可用页面使用的能力时,它可以浏览"干净"页面的列表,并根据它们的使用时间以及使用哪种内存他们将这些页面移至空闲列表。
一旦将内存页放置在空闲列表中,它们就不再与以前的内容相关联。如果程序带有引用,则该页面以前服务的内存位置会导致该程序出现重大故障,并且(可能完全不同的)页面将从空闲列表中获取,并且数据将从磁盘读取到页面中。完成此操作后,该页面实际上仍是"干净的",因为尚未对其进行修改。如果VM选择在交换时将该页面用于RAM中的其他页面,则该页面将再次被"脏污",或者如果应用程序写入该页面,它将被"脏污"。然后该过程再次开始。
同样,对于敏感于业务/事务/在线/延迟的环境中的服务器应用程序,互换性非常可怕。当我有16GB的RAM盒而不运行很多浏览器和GUI时,通常我希望所有应用程序几乎都固定在内存中。我的RAM大部分是8-10GB的Java堆,我从不希望将其分页到磁盘,可用的碎片是诸如mingetty之类的进程(但即使在那里,这些应用程序中的glibc页面也被其他应用程序共享,实际上因此,即使这些无用进程的RSS大小也大多是共享的,使用过的页面)。我通常看不到实际清理掉的16GB内存中有多少10MB可以交换。我建议服务器的交换数量非常低或者交换率为零-未使用的页面应占总RAM的一小部分,并尝试回收相对少量的RAM用于缓冲区高速缓存,这有可能会交换应用程序页面并降低延迟。正在运行的应用程序。