Peter Eisentraut Asked: 2010-01-13 06:16:55 +0800 CST2010-01-13 06:16:55 +0800 CST 2010-01-13 06:16:55 +0800 CST 默认关闭Linux OOM杀手? 772 Linux 上的 OOM 杀手经常对各种应用程序造成严重破坏,而且似乎在内核开发方面并没有做太多的工作来改善这一点。作为设置新服务器vm.overcommit_memory=2时的最佳实践,反转内存过度使用的默认设置不是更好吗,即关闭它(那些用例是你知道你想要过度使用的地方? 作为奖励,由于在情况下的行为vm.overcommit_memory=2取决于vm.overcommit_ratio和交换空间,对于调整后两者的大小以使整个设置保持合理工作,什么是一个好的经验法则? linux memory kernel oom 4 个回答 Voted An̲̳̳drew 2010-10-26T11:36:21+08:002010-10-26T11:36:21+08:00 一个有趣的类比(来自http://lwn.net/Articles/104179/): 一家飞机公司发现,用更少的燃料驾驶飞机会更便宜。飞机会更轻,使用更少的燃料和金钱。然而,在极少数情况下,燃料量不足,飞机会坠毁。该公司的工程师通过开发一种特殊的 OOF(燃料不足)机制解决了这个问题。在紧急情况下,一名乘客被选中并被抛出飞机。(必要时,重复该程序。)大量的理论被开发出来,许多出版物专门讨论如何正确选择被驱逐的受害者。受害者应该随机选择吗?还是应该选择最重的人?还是最老的?如果乘客为了不被弹出而付费,让受害者成为船上最贫穷的人?例如,如果选择了最重的人,如果是飞行员,是否应该有一个特殊的例外?头等舱乘客应该被豁免吗?现在OOF机制存在,它会时不时地启动,即使没有燃料短缺也会弹出乘客。工程师们仍在精确研究这种故障是如何引起的。 womble 2010-01-13T13:31:22+08:002010-01-13T13:31:22+08:00 只有当您的系统超载时,OOM 杀手才会造成严重破坏。给它足够的交换空间,不要运行突然决定吃掉大量内存的应用程序,你不会有问题。 具体回答您的问题: 我认为在一般情况下关闭过度使用不是一个好主意。很少有应用程序被编写来正确处理brk(2)(以及使用它的包装器,例如malloc(3))返回错误。当我在上一份工作中对此进行实验时,人们认为让所有东西都能够处理内存不足错误比仅仅处理 OOM 的后果(在我们的例子中,如果发生 OOM,这比不得不重新启动偶尔的服务要糟糕得多——我们不得不重新启动整个集群,因为 GFS 是一堆冒着蒸汽的粪便)。 您希望对任何过度使用内存的进程进行过度使用。这里最常见的两个罪魁祸首是 Apache 和 JVM,但许多应用程序或多或少地做到了这一点。他们认为他们在未来的某个时候可能需要大量的内存,所以他们马上就抓住了一大块。在启用了过量使用的系统上,内核会“嗯,无论如何,当你真正想要写入那些页面时来打扰我”并且没有发生任何不好的事情。在 overcommit-off 系统上,内核说“不,你不能有那么多内存,如果你在未来的某个时候碰巧写了所有的东西,我已经筋疲力尽了,所以你没有内存!” 并且分配失败。既然什么都没有那里出现“哦,好的,我可以拥有这个更少量的进程数据段吗?”,然后进程要么(a)退出内存不足错误,要么(b)不检查返回代码malloc,认为可以走,写入无效的内存位置,导致segfault。值得庆幸的是,JVM 在启动时完成了所有 prealloc(因此您的 JVM 要么立即启动,要么立即终止,您通常会注意到这一点),但 Apache 对每个新子节点都做了一些时髦的事情,这可能会在生产中产生令人兴奋的效果(不可重现的“不处理连接“类型的兴奋)。 我不想将我的 overcommit_ratio 设置为高于默认值 50%。同样,根据我的测试,虽然将其设置在 80 或 90 左右可能听起来很酷,但内核在不方便的时候需要大量内存,并且具有高过载率的满载系统可能没有足够的备用内存当内核需要它时(导致恐惧、瘟疫和糟糕)。因此,玩 overcommit 引入了一种新的、更有趣的故障模式——而不是在内存不足时重新启动任何被 OOMed 的进程,现在你的机器崩溃了,导致机器上的所有东西都中断。惊人的! 无过度使用系统中的交换空间取决于您的应用程序需要多少已请求但未使用的内存,以及健康的安全裕度。确定在特定情况下需要什么作为练习留给读者。 基本上,我的经验是关闭过度使用是一个很好的实验,但在实践中很少像理论上听起来那样有效。这与我在内核中使用其他可调参数的经验非常吻合——Linux 内核开发人员几乎总是比您更聪明,并且默认值在绝大多数情况下工作得最好。不要管它们,而是去查找哪个进程有泄漏并修复它。 weird 2010-03-23T13:22:16+08:002010-03-23T13:22:16+08:00 嗯,我并不完全相信支持过度使用和 OOM 杀手的论点......当 womble 写道, “只有在系统过载时,OOM 杀手才会造成严重破坏。给它足够的交换空间,不要运行突然决定占用大量 RAM 的应用程序,这样就不会有问题。” 他将描述一个环境场景,其中不强制执行过度使用和 OOM 杀手,或者不“真正”采取行动(如果所有应用程序都根据需要分配内存,并且有足够的虚拟内存要分配,内存写入将紧跟内存分配而无需错误,因此即使启用了过度使用策略,我们也无法真正谈论过度使用的系统)。这是关于一个隐含的承认,即过量使用和 OOM 杀手在不需要他们的干预时效果最好,据我所知(我承认我不能说太多......)。Morover,在预分配内存时提到具有特定行为的应用程序让我认为可以在分发级别调整特定处理,而不是使用默认值, 对于 JVM 而言,嗯,它是一个虚拟机,在某种程度上它需要在启动时分配它所需的所有资源,因此它可以为其应用程序创建它的“假”环境,并将其可用资源与主机分离环境,尽可能。因此,最好让它在启动时失败,而不是在一段时间后由于“外部”OOM条件(由过度提交/OOM杀手/其他原因引起),或者无论如何都会因为这种干扰它自己的条件而遭受痛苦内部 OOM 处理策略(通常,VM 应该从一开始就获得任何所需的资源,并且主机系统应该“忽略”它们直到结束,就像与显卡共享任何数量的物理内存一样,永远不会 - 也不能- 被操作系统触及)。 关于 Apache,我怀疑让整个服务器偶尔被杀死并重新启动比让一个孩子和一个连接从它(=孩子的/连接的)开始失败(好像它是一个全新的实例)更好在另一个实例运行一段时间后创建的 JVM)。我想最好的“解决方案”可能取决于特定的上下文。例如,考虑到电子商务服务,有时与购物图表的一些连接随机失败而不是丢失整个服务可能要好得多,例如,存在中断正在进行的订单完成的风险,或者(可能更糟)支付过程,以及案件的所有后果(可能是无害的,但也可能是有害的 - 当然,当出现问题时, 同样,在工作站上,消耗最多资源的进程,因此尾随成为 OOM 杀手的首选,可能是内存密集型应用程序,例如视频转码器或渲染软件,可能是唯一的应用程序用户希望不受影响。这种考虑暗示我 OOM 杀手默认策略过于激进。它使用“最差拟合”方法,这在某种程度上类似于某些文件系统的方法(OOMK 尝试并尽可能多地释放内存,同时减少被杀死的子进程的数量,以防止在短时间内进一步干预,如以及 fs 可以为某个文件分配比实际需要更多的磁盘空间,以防止在文件增长时进一步分配,从而在某种程度上防止碎片)。 但是,我认为相反的策略(例如“最合适”的方法)可能更可取,因此可以释放特定点所需的确切内存,而不必为“大”进程而烦恼,这很可能是浪费内存,但也可能不知道,并且内核不知道(嗯,我可以想象跟踪页面访问次数和时间可以暗示进程是否正在分配它不再需要的内存,所以猜测一个进程是否正在浪费内存或只是使用大量内存,但访问延迟应在 cpu 周期上加权,以区分内存浪费与内存和cpu 密集型应用程序,但是,虽然可能不准确,但这种启发式方法可能会产生过多的开销)。 此外,杀死较少可能的进程总是一个好的选择可能不是真的。例如,在桌面环境中(例如,让我们考虑资源有限的上网本或上网本),用户可能正在运行带有多个选项卡的浏览器(因此,内存消耗 - 假设这是 OOMK 的第一个选择) ,加上一些其他应用程序(一个没有保存数据的文字处理器、一个邮件客户端、一个 pdf 阅读器、一个媒体播放器,......),加上一些(系统)守护程序,加上一些文件管理器实例。现在,发生了 OOM 错误,并且 OOMK 选择在用户通过网络执行被认为“重要”的事情时终止浏览器......用户会感到失望。另一方面,关闭少数文件管理器' 无论如何,我认为应该使用户能够自行决定要做什么。在桌面(=交互式)系统中,这应该相对容易做到,只要保留足够的资源来要求用户关闭任何应用程序(但即使关闭几个选项卡就足够了)并处理他的选择(一个选项可以包括创建一个额外的交换文件,如果有足够的空间)。对于服务(以及一般情况),我还考虑了两个进一步可能的增强:一个是记录 OOM 杀手干预,以及以这样一种方式启动/分叉失败的进程可以很容易地调试失败(例如,一个 API 可以通知发布新进程创建或分叉的进程 - 因此,像 Apache 这样的服务器,带有适当的补丁,可以为某些错误提供更好的日志记录);这可以独立于过度使用/OOMK 来完成;其次,但不重要的是,可以建立一种机制来微调 OOMK 算法 - 我知道在某种程度上,可以在逐个进程的基础上定义特定的策略,但我的目标是“集中式”配置机制,基于一个或多个应用程序名称(或 ID)列表来识别相关进程并赋予它们一定程度的重要性(根据列出的属性);这种机制也应该(或至少可以)分层,以便可以有一个顶层用户定义列表、一个系统(分发)定义列表和(底层)应用程序定义条目(所以,例如,DE 文件管理器可以指示 OOMK 安全地杀死任何实例, 此外,可以提供一个 API 以允许应用程序在运行时提高或降低其“重要性”级别(相对于内存管理目的和无论执行优先级),例如,一个字处理器可以从低“重要性”,但在刷新到文件或正在执行写操作之前保留了一些数据,并且一旦此类操作结束,重要性就会再次降低(类似地,文件管理器可以在从刚刚通过时更改级别liting 文件来处理数据,反之亦然,而不是使用单独的进程,并且 Apache 可以为不同的子进程赋予不同级别的重要性,或者根据系统管理员决定并通过 Apache 或任何其他类型的服务器公开的某些策略更改子状态- 设置)。当然,这样的 API 可能并且将会被滥用/误用,但我认为与内核任意杀死进程以释放内存相比,这是一个小问题,而没有任何有关系统正在发生的事情的相关信息(以及内存消耗/创建时间等) '对我来说不够相关或'验证')-只有用户、管理员和程序编写者才能真正确定是否出于某种原因“仍然需要”进程、原因是什么和/或应用程序是否处于领先状态如果被杀,数据丢失或其他损害/麻烦;然而,还可以做出一些假设,例如寻找由进程获取的某种资源(文件描述符、网络套接字等),并通过挂起的操作来判断进程是否应该处于高于“状态”的状态。一套, 或者,只是避免过度使用,让内核做内核必须做的事情,分配资源(但不要像 OOM 杀手那样随意拯救它们),调度进程,防止饥饿和死锁(或从它们中拯救),确保完全抢占和内存空间分离,等等...... 我还要多说一些关于过度使用方法的内容。从其他讨论中,我认为关于过度使用的主要担忧之一(作为想要它的理由和作为可能的麻烦的根源)包括分叉处理:老实说,我不知道复制到底是怎么回事-写入策略已实施,但我认为任何激进(或乐观)策略都可能通过类似交换的局部性策略来缓解。也就是说,除了克隆(和调整)分叉的进程代码页和调度结构之外,还可以在实际写入之前复制一些其他数据页,在父进程访问的那些页面中进行选择以进行更频繁的写入(即,使用计数器进行写操作)。 一切,当然,恕我直言。 dinkey jhanwar 2017-03-09T03:04:39+08:002017-03-09T03:04:39+08:00 如果您的内存被进程耗尽到可能威胁系统稳定性的程度,那么OOM杀手就会出现。OOM Killer 的任务是杀死进程,直到释放足够的内存以供进程的其余部分顺利运行。OOM Killer 必须选择要杀死的“最佳”进程。这里的“最佳”是指在杀死时将释放最大内存并且对系统而言也是最不重要的进程。主要目标是杀死最少数量的进程,从而最大限度地减少造成的损害,同时最大限度地释放内存量。为了促进这一点,内核为每个进程维护 oom_score。可以在pid目录下的/proc文件系统中看到每个进程的oom_score # cat /proc/10292/oom_score 任何进程的 oom_score 值越高,它在内存不足的情况下被 OOM Killer 杀死的可能性就越高。 信用:- Linux 内核正在启动 OOM 杀手
一个有趣的类比(来自http://lwn.net/Articles/104179/):
只有当您的系统超载时,OOM 杀手才会造成严重破坏。给它足够的交换空间,不要运行突然决定吃掉大量内存的应用程序,你不会有问题。
具体回答您的问题:
brk
(2)(以及使用它的包装器,例如malloc
(3))返回错误。当我在上一份工作中对此进行实验时,人们认为让所有东西都能够处理内存不足错误比仅仅处理 OOM 的后果(在我们的例子中,如果发生 OOM,这比不得不重新启动偶尔的服务要糟糕得多——我们不得不重新启动整个集群,因为 GFS 是一堆冒着蒸汽的粪便)。基本上,我的经验是关闭过度使用是一个很好的实验,但在实践中很少像理论上听起来那样有效。这与我在内核中使用其他可调参数的经验非常吻合——Linux 内核开发人员几乎总是比您更聪明,并且默认值在绝大多数情况下工作得最好。不要管它们,而是去查找哪个进程有泄漏并修复它。
嗯,我并不完全相信支持过度使用和 OOM 杀手的论点......当 womble 写道,
“只有在系统过载时,OOM 杀手才会造成严重破坏。给它足够的交换空间,不要运行突然决定占用大量 RAM 的应用程序,这样就不会有问题。”
他将描述一个环境场景,其中不强制执行过度使用和 OOM 杀手,或者不“真正”采取行动(如果所有应用程序都根据需要分配内存,并且有足够的虚拟内存要分配,内存写入将紧跟内存分配而无需错误,因此即使启用了过度使用策略,我们也无法真正谈论过度使用的系统)。这是关于一个隐含的承认,即过量使用和 OOM 杀手在不需要他们的干预时效果最好,据我所知(我承认我不能说太多......)。Morover,在预分配内存时提到具有特定行为的应用程序让我认为可以在分发级别调整特定处理,而不是使用默认值,
对于 JVM 而言,嗯,它是一个虚拟机,在某种程度上它需要在启动时分配它所需的所有资源,因此它可以为其应用程序创建它的“假”环境,并将其可用资源与主机分离环境,尽可能。因此,最好让它在启动时失败,而不是在一段时间后由于“外部”OOM条件(由过度提交/OOM杀手/其他原因引起),或者无论如何都会因为这种干扰它自己的条件而遭受痛苦内部 OOM 处理策略(通常,VM 应该从一开始就获得任何所需的资源,并且主机系统应该“忽略”它们直到结束,就像与显卡共享任何数量的物理内存一样,永远不会 - 也不能- 被操作系统触及)。
关于 Apache,我怀疑让整个服务器偶尔被杀死并重新启动比让一个孩子和一个连接从它(=孩子的/连接的)开始失败(好像它是一个全新的实例)更好在另一个实例运行一段时间后创建的 JVM)。我想最好的“解决方案”可能取决于特定的上下文。例如,考虑到电子商务服务,有时与购物图表的一些连接随机失败而不是丢失整个服务可能要好得多,例如,存在中断正在进行的订单完成的风险,或者(可能更糟)支付过程,以及案件的所有后果(可能是无害的,但也可能是有害的 - 当然,当出现问题时,
同样,在工作站上,消耗最多资源的进程,因此尾随成为 OOM 杀手的首选,可能是内存密集型应用程序,例如视频转码器或渲染软件,可能是唯一的应用程序用户希望不受影响。这种考虑暗示我 OOM 杀手默认策略过于激进。它使用“最差拟合”方法,这在某种程度上类似于某些文件系统的方法(OOMK 尝试并尽可能多地释放内存,同时减少被杀死的子进程的数量,以防止在短时间内进一步干预,如以及 fs 可以为某个文件分配比实际需要更多的磁盘空间,以防止在文件增长时进一步分配,从而在某种程度上防止碎片)。
但是,我认为相反的策略(例如“最合适”的方法)可能更可取,因此可以释放特定点所需的确切内存,而不必为“大”进程而烦恼,这很可能是浪费内存,但也可能不知道,并且内核不知道(嗯,我可以想象跟踪页面访问次数和时间可以暗示进程是否正在分配它不再需要的内存,所以猜测一个进程是否正在浪费内存或只是使用大量内存,但访问延迟应在 cpu 周期上加权,以区分内存浪费与内存和cpu 密集型应用程序,但是,虽然可能不准确,但这种启发式方法可能会产生过多的开销)。
此外,杀死较少可能的进程总是一个好的选择可能不是真的。例如,在桌面环境中(例如,让我们考虑资源有限的上网本或上网本),用户可能正在运行带有多个选项卡的浏览器(因此,内存消耗 - 假设这是 OOMK 的第一个选择) ,加上一些其他应用程序(一个没有保存数据的文字处理器、一个邮件客户端、一个 pdf 阅读器、一个媒体播放器,......),加上一些(系统)守护程序,加上一些文件管理器实例。现在,发生了 OOM 错误,并且 OOMK 选择在用户通过网络执行被认为“重要”的事情时终止浏览器......用户会感到失望。另一方面,关闭少数文件管理器'
无论如何,我认为应该使用户能够自行决定要做什么。在桌面(=交互式)系统中,这应该相对容易做到,只要保留足够的资源来要求用户关闭任何应用程序(但即使关闭几个选项卡就足够了)并处理他的选择(一个选项可以包括创建一个额外的交换文件,如果有足够的空间)。对于服务(以及一般情况),我还考虑了两个进一步可能的增强:一个是记录 OOM 杀手干预,以及以这样一种方式启动/分叉失败的进程可以很容易地调试失败(例如,一个 API 可以通知发布新进程创建或分叉的进程 - 因此,像 Apache 这样的服务器,带有适当的补丁,可以为某些错误提供更好的日志记录);这可以独立于过度使用/OOMK 来完成;其次,但不重要的是,可以建立一种机制来微调 OOMK 算法 - 我知道在某种程度上,可以在逐个进程的基础上定义特定的策略,但我的目标是“集中式”配置机制,基于一个或多个应用程序名称(或 ID)列表来识别相关进程并赋予它们一定程度的重要性(根据列出的属性);这种机制也应该(或至少可以)分层,以便可以有一个顶层用户定义列表、一个系统(分发)定义列表和(底层)应用程序定义条目(所以,例如,DE 文件管理器可以指示 OOMK 安全地杀死任何实例,
此外,可以提供一个 API 以允许应用程序在运行时提高或降低其“重要性”级别(相对于内存管理目的和无论执行优先级),例如,一个字处理器可以从低“重要性”,但在刷新到文件或正在执行写操作之前保留了一些数据,并且一旦此类操作结束,重要性就会再次降低(类似地,文件管理器可以在从刚刚通过时更改级别liting 文件来处理数据,反之亦然,而不是使用单独的进程,并且 Apache 可以为不同的子进程赋予不同级别的重要性,或者根据系统管理员决定并通过 Apache 或任何其他类型的服务器公开的某些策略更改子状态- 设置)。当然,这样的 API 可能并且将会被滥用/误用,但我认为与内核任意杀死进程以释放内存相比,这是一个小问题,而没有任何有关系统正在发生的事情的相关信息(以及内存消耗/创建时间等) '对我来说不够相关或'验证')-只有用户、管理员和程序编写者才能真正确定是否出于某种原因“仍然需要”进程、原因是什么和/或应用程序是否处于领先状态如果被杀,数据丢失或其他损害/麻烦;然而,还可以做出一些假设,例如寻找由进程获取的某种资源(文件描述符、网络套接字等),并通过挂起的操作来判断进程是否应该处于高于“状态”的状态。一套,
或者,只是避免过度使用,让内核做内核必须做的事情,分配资源(但不要像 OOM 杀手那样随意拯救它们),调度进程,防止饥饿和死锁(或从它们中拯救),确保完全抢占和内存空间分离,等等......
我还要多说一些关于过度使用方法的内容。从其他讨论中,我认为关于过度使用的主要担忧之一(作为想要它的理由和作为可能的麻烦的根源)包括分叉处理:老实说,我不知道复制到底是怎么回事-写入策略已实施,但我认为任何激进(或乐观)策略都可能通过类似交换的局部性策略来缓解。也就是说,除了克隆(和调整)分叉的进程代码页和调度结构之外,还可以在实际写入之前复制一些其他数据页,在父进程访问的那些页面中进行选择以进行更频繁的写入(即,使用计数器进行写操作)。
一切,当然,恕我直言。
信用:- Linux 内核正在启动 OOM 杀手