我知道虚拟内存的概念。通过按需分页(取决于 vm.overcommit_memory),您可以分配比可用 RAM 更多的内存。除非您“触摸”页面,否则不会真正发生任何事情。否则我猜有一个页面错误,然后将物理内存用于页面框架。但这不知何故意味着,如果系统内存紧张,它只会调出最近使用的东西并正常工作。
怎么可能需要杀死一个进程?是否会因为 mlock()-ed 内存过多而发生。垃圾过多后是否调用OOM?或者换个说法:触发 OOM 杀手背后的启发式方法到底是什么?
我读到您可以执行“echo 1 > memory.oom_control”或“echo -17 > /proc/PID/oom_adj”来禁用它。这意味着什么?机器可能会在一段时间内完全没有响应。但是,如果有问题的进程以某种方式检测到它没有取得进展,它也可能暂时停止消耗内存(那么快),最终一切都应该重新开始工作还是我弄错了?
在我的场景中,只有一个进程(具有巨大的内存缓存)。当然,该数据不是持久的,但我仍宁愿不重新启动该过程(并重新加载该数据)。
您似乎对虚拟内存和过度使用的关系感到困惑。
物理内存由计算机中的 RAM 芯片组成。物理上不可能同时使用比物理内存更多的内存。然而,自 1970 年代后期以来,出现了虚拟内存,其中系统会将一些数据从物理内存移动到磁盘,从而存储实际上没有被使用的内存,因此物理内存可以用于其他用途。发生这种情况时,程序不能立即使用换出的数据;当他们无论如何都尝试这样做时,处理器将产生页面错误,导致操作系统将所需的数据从交换加载回物理内存。
通过使用虚拟内存,可以使用的动态数据总量扩展到物理内存加上交换空间的大小。虽然这允许系统同时运行更多程序,但实际使用的内存量永远不会超过总可用虚拟内存(即 RAM + 交换空间)
原则上,内核应该跟踪程序向它请求的内存量,并且一旦它的簿记告诉它所有内存都已分配,它应该拒绝更多内存的请求,即使它可能没有全部被使用. 大多数其他内核都这样做,因此它们没有 OOM 杀手(因为它们不需要)。
但是,程序从内核分配内存的系统调用不是按字节分配内存的。它按更大的块分配它。相反,大多数程序用于获取内存的实际实现(
malloc()
C 库函数)确实允许程序按字节分配内存。这意味着大多数程序,当他们要求一些内存时,最终会malloc()
分配比他们实际需要的更多的内存。此外,一个不错的malloc()
实现将使用一些启发式方法将较小和较大的分配分开,以便内存碎片不会太糟糕,但这样做需要它从内核请求更多内存,从而加剧了问题。由于这些和其他影响,如果不过度使用,将会有大量内存被分配但永远不会被使用。过度使用的想法是,您可以安全地分配比系统可用的虚拟内存总量更多的内存,而不会适得其反。本质上,内核声称它允许分配,即使它知道它不能兑现该承诺,假设它不需要完全兑现这些承诺。但是,无法预测可以过度使用(分配)而不会出错的确切数量。因此,当内核检测到程序试图使用分配给它们的所有内存时,内核将不得不违背其承诺。这就是OOM杀手的用武之地。
这是否是一个好主意还有待商榷。当系统内存不足时,就会出现问题。如果这是某个应用程序试图分配更多内存但内核已经保留了所有内容的情况,那么该特定应用程序可能会崩溃。如果这恰好是你的 X 服务器,那你就倒霉了。至少如果有一个 OOM 杀手,它可以决定要杀死哪个进程,而不是在分配错误后出现问题;并且OOM杀手有一些逻辑可以避免杀死重要的进程,比如你的X服务器......
但是,如果您愿意,可以使用一些 sysctl 旋钮来关闭过度使用,但您认为这是个坏主意。