TL; DR
简短的临时/答案
- 最简单:具有较小的交换分区,并避免内核试图通过从慢速存储运行进程来达到没有内存限制的谎言。
- 进行大量交换后,OOM(内存管理器外)无法足够快地采取行动。通常,它根据虚拟内存进行计费,根据我过去的经验,它直到整个交换被填满才杀死了所有东西,因此系统运行缓慢。
- 需要大量的休眠时间吗?
- 尝试/有问题:设置一些限制(例如check
ulimit -v
,并且可以使用中的as
选项设置硬限制或软限制limits.conf
)。过去,这种方法可以很好地工作,但是由于WebKit的引入gigacage
,许多gnome应用程序现在都希望地址空间不受限制并且无法运行!
- 试图/问题:在过载策略和比例是另一种方式来尝试管理和减轻这个(如
sysctl vm.overcommit_memory
,sysctl vm.overcommit_ratio
但这种方法并没有为我工作了。
- 困难/复杂:尝试将cgroup优先级应用于最重要的进程(例如ssh),但是目前对于cgroup v1似乎很麻烦(希望v2会更容易)...
我还发现:
长期解决方案
等待并希望一些上游补丁进入稳定的发行版内核。还希望发行版供应商能够更好地调整内核默认设置,并更好地利用系统化的cgroup在桌面版本中对GUI响应进行优先级排序。
一些有趣的补丁:
因此,错误的不仅仅是错误的用户空间代码和发行版config / defaults-内核可以更好地解决这一问题。
对已经考虑的选项的评论
1)禁用交换
建议至少提供一个小的交换分区(我们是否真的需要在现代系统上进行交换?)。禁用交换功能不仅可以防止交换出未使用的页面,而且还可能会影响内核的默认启发式过量分配策略(用于分配内存)(Overcommit_memory = 0中的启发式意味着什么?),因为该启发式确实会影响交换页面。如果没有交换,过量使用仍然可以在启发式(0)或始终(1)模式下工作,但是不交换和永不(2)过量使用策略的组合可能是一个糟糕的主意。因此,在大多数情况下,没有交换可能会损害性能。
例如,考虑一个长期运行的过程,该过程最初涉及内存以进行一次性工作,但随后又无法释放该内存并保持后台运行。内核将不得不为此使用RAM,直到进程结束。如果不进行任何交换,内核将无法为其换出其他实际需要主动使用RAM的内存。还请考虑有多少开发人员是懒惰的,并且在使用后没有明确释放内存。
3)设置最大内存ulimit
它仅适用于每个进程,并且这可能是一个合理的假设,即进程不应请求系统物理上拥有的更多内存!因此,在仍然慷慨设置的同时,阻止一个疯狂的过程触发颠簸可能是有用的。
4)将重要程序(X11,bash,kill,top等)保留在内存中,切勿交换这些程序
这是个好主意,但是这些程序会占用他们没有积极使用的内存。如果程序仅请求少量的内存,则可以接受。
systemd 232版本刚刚添加了一些选项,使之成为可能:我认为可以使用'MemorySwapMax = 0'来防止像ssh这样的单元(服务)交换出任何内存。
尽管如此,能够对存储器访问进行优先级排序会更好。
详细说明
linux内核已针对服务器工作负载进行了更优化,因此令人遗憾的是,GUI响应能力是次要问题... Ubuntu 16.04 LTS桌面版上的内核内存管理设置似乎与其他服务器版没有什么不同。它甚至与通常用作服务器的RHEL / CentOS 7.2中的默认值匹配。
OOM,ulimit和权衡完整性以提高响应能力
交换颠簸(当内存的工作集(即,在给定的短时间内要读写的页面超过物理RAM)时)将始终锁定存储I / O-任何内核向导都无法在不杀死进程的情况下从中保存系统一两个...
我希望新近出现的内核中的Linux OOM调整能够认识到该工作集超出了物理内存的状况,并杀死了一个进程。否则,将发生严重的问题。问题是,对于一个大的交换分区,它看起来好像系统仍然有空间,而内核只是在忙于提交并且仍在处理内存请求,但是工作集可能会溢出到交换中,从而有效地尝试像对待存储一样它是RAM。
在服务器上,它接受确定的,缓慢的,不丢失数据的折衷所带来的性能损失。在台式机上,权衡是不同的,用户希望保留一些数据丢失(过程牺牲)以保持响应速度。
这是关于OOM的一个很好笑的类比:oom_pardon,也不要杀死我的xlock
顺便提一句,这OOMScoreAdjust
是另一个有助于减轻体重并避免OOM终止进程的系统选项,被认为更重要。
缓冲写回
我认为“ 使后台写回不吸引 ”将有助于避免某些问题:进程占用内存导致另一个交换(写到磁盘),而批量写到磁盘则使其他任何需要IO的东西停滞了。它本身不是引发问题的原因,但确实会增加响应能力的整体下降。
限制
ulimits的一个问题是,记帐限制适用于虚拟内存地址空间(这意味着将物理空间和交换空间结合在一起)。按照man limits.conf
:
rss
maximum resident set size (KB) (Ignored in Linux 2.4.30 and
higher)
因此,将ulimit设置为仅适用于物理RAM的使用似乎不再有用。因此
as
address space limit (KB)
似乎是唯一值得尊敬的可调参数。
不幸的是,如WebKit / Gnome的示例所详述,如果虚拟地址空间分配受到限制,某些应用程序将无法运行。
cgroups应该在将来提供帮助吗?
当前,它看起来很麻烦,但是可以启用一些内核cgroup标志cgroup_enable=memory swapaccount=1
(例如在grub config中),然后尝试使用cgroup内存控制器来限制内存使用。
cgroup具有比“ ulimit”选项更高级的内存限制功能。CGroup v2指出了尝试改进ulimits如何工作的暗示。
内存+交换计费和限制的组合已由对交换空间的实际控制所取代。
可以通过systemd资源控制选项设置CGroup 选项。例如:
其他有用的选项可能是
这些有一些缺点:
- 高架。当前的docker文档简要提到了1%的额外内存使用和10%的性能下降(可能在内存分配操作方面-并没有具体说明)。
- Cgroup / systemd的东西最近已被大量修改,因此上游的变化意味着Linux发行版供应商可能正在等待其解决。
他们建议在CGroup v2中,这memory.high
是控制和管理进程组内存使用的好选择。但是,这句话表明监视内存压力情况需要更多的工作(截至2015年)。
需要一种内存压力度量(由于缺少内存而导致工作负载受到多少影响),以确定工作负载是否需要更多内存;不幸的是,内存压力监视机制尚未实现。
鉴于systemd和cgroup用户空间工具很复杂,我还没有找到一种简单的方法来设置合适的东西并进一步利用它。Ubuntu的cgroup和systemd文档不是很好。未来的工作应该是桌面版本的发行版,以利用cgroup和systemd,以便在高内存压力下,ssh和X-Server / window manager组件具有对CPU,物理RAM和存储IO的更高优先级访问,从而避免与进程竞争忙着交换。内核的CPU和I / O优先级功能已经存在了一段时间。似乎缺少对物理RAM的优先访问权。
但是,甚至没有适当设置CPU和IO优先级!据我所知,当我检查systemd的cgroup限制,cpu份额等时,Ubuntu并未按照任何预先定义的优先顺序进行烘烤。例如,我跑了:
systemctl show dev-mapper-Ubuntu\x2dswap.swap
我将其与ssh,samba,gdm和nginx的相同输出进行了比较。当发生崩溃时,GUI和远程管理控制台等重要内容必须与所有其他进程同等地战斗。
我在16GB RAM系统上的示例内存限制
我想启用休眠模式,因此需要一个很大的交换分区。因此尝试用ulimit等缓解。
极限
我把* hard as 16777216
在/etc/security/limits.d/mem.conf
这样没有任何单一的过程将被允许以请求更多的内存比物理上可能的。我不会阻止整体崩溃,但是如果没有,则只有一个贪婪的内存使用或内存泄漏的单个进程可能会导致整体崩溃。例如gnome-contacts
,在执行诸如从交换服务器更新全局地址列表之类的日常工作时,我已经看到占用超过8GB的内存...
从表中可以看出ulimit -S -v
,许多发行版都将此硬限制和软限制设置为“无限制”,从理论上讲,一个进程最终可能会请求大量内存,但只能主动使用一个子集,并高兴地认为已分配了24GB RAM,系统只有16GB。上面的硬限制将导致在内核拒绝其贪婪的推测性内存请求时,本可以正常运行的进程中止。
但是,它还会捕获诸如gnome联系人之类的疯狂事件,而不是失去桌面响应能力,而是出现“没有足够的可用内存”错误:
设置地址空间(虚拟内存)的ulimit的复杂性
不幸的是,一些开发人员喜欢假装虚拟内存是无限资源,并且在虚拟内存上设置ulimit可能会破坏某些应用程序。例如,WebKit(某些gnome应用程序所依赖的WebKit)添加了一项gigacage
安全功能,该功能试图分配大量的虚拟内存,并且会FATAL: Could not allocate gigacage memory
出现厚脸皮的提示错误Make sure you have not set a virtual memory limit
。解决方法GIGACAGE_ENABLED=no
放弃了安全性好处,但是同样,不允许用户限制虚拟内存分配也放弃了一项安全性功能(例如,可以防止拒绝服务的资源控制)。具有讽刺意味的是,在巨无霸和gnome开发人员之间,他们似乎忘记了限制内存分配本身就是一种安全控制。令人遗憾的是,我注意到依赖于千兆字节的gnome应用程序不会费力地显式请求更高的限制,因此在这种情况下,即使是软限制也无法解决问题。
公平地说,如果内核能够更好地完成基于驻留内存使用而不是虚拟内存的内存分配拒绝的工作,那么假装虚拟内存是无限的就没有那么危险了。
过量使用
如果您希望拒绝应用程序的内存访问,并希望停止过量使用,请使用以下命令测试系统在高内存压力下的行为。
就我而言,默认的提交比率是:
$ sysctl vm.overcommit_ratio
vm.overcommit_ratio = 50
但是,只有在更改策略以禁用过量使用和应用比率时,它才完全生效
sudo sysctl -w vm.overcommit_memory=2
该比率意味着总共只能分配24GB内存(16GB RAM * 0.5 + 16GB SWAP)。因此,我可能永远不会看到OOM出现,并且实际上不太可能让进程不断地交换访问内存。但是我也可能会牺牲整体系统效率。
鉴于开发人员通常无法正常处理操作系统拒绝内存分配请求的情况,这将导致许多应用程序崩溃。它权衡了由于崩溃(硬重置后失去所有工作)而导致的锁定被抽出的偶然风险与各种应用崩溃的更频繁风险之间的平衡。在我的测试中,它没有太大帮助,因为当系统承受内存压力时,台式机本身崩溃了,并且无法分配内存。但是,至少控制台和SSH仍然有效。
VM如何过量使用内存如何工作具有更多信息。
sudo sysctl -w vm.overcommit_memory=0
考虑到整个桌面图形堆栈及其中的应用程序仍然崩溃,我选择恢复为默认值。