如何确定给定内存限制的 Node --max_old_space_size ?

Dav*_*ser 5 v8 node.js

我们在硬内存上限为 1GB、2GB 或 4GB 的 Docker 容器内运行 Node 进程。每个容器通常只运行一个 Node 进程(可能还加上一个微小的 shell 脚本包装器)。为了解决这个问题,我们假设 Node 进程永远不会派生更多进程。

\n\n

对于较大的容器,如果我们自己不设置 --max_old_space_size ,那么在我们使用的 Node 版本(在 64 位机器上)中,它默认为 1400MB。(在更高版本的 Node 中,这将更改为 2048MB 。)

\n\n

理想情况下,我们希望 Node 进程能够使用尽可能多的容器,而不会超出和耗尽内存。问题是 \xe2\x80\x94 我们应该使用什么数字?我的理解是,这个特定的标志调整 Node 使用的最大内存池之一的大小,但它不是唯一的池 \xe2\x80\x94\xc2\xa0eg,有一个“非旧内存池” " 堆的一部分,还有堆栈等。设置此标志时,我应该从容器的大小中减去多少,以便远离 cgroup 内存限制,但仍然最大限度地利用内存量允许在这个容器中吗?

\n\n

我确实注意到,从定义 kMaxOldSpaceSizeHugeMemoryDe​​vice 的同一位置来看,默认的“最大半空间”似乎是 16MB,默认的“最大可执行文件大小”是 512MB。所以我怀疑这意味着在确定该标志的值时我应该从容器的内存限制中至少减去 528。但 Node 肯定还有其他使用内存的方式吗?

\n\n

(更具体地说,我们是一家托管服务公司,向我们的用户出售特定大小的容器,其中大多数用户将它们用于 Node 进程。我们希望能够建议我们的客户设置什么标志,以便他们既不会被我们的限制所杀死,也不会为节点的配置不允许他们实际使用的容量向我们付费。)

\n

jmr*_*mrk 4

不幸的是,这个问题没有特别令人满意的答案。

您找到的常量控制垃圾收集堆的大小,但正如您已经猜到的,有很多方法可以消耗不属于该堆的内存:

  • 例如,大字符串和大 TypedArray 通常由嵌入器(即节点及其模块,而不是 V8 本身)管理,并且位于 GC 堆之外。
  • 一般来说,节点模块可以消耗它们想要的任何内存。也许您不想限制客户可以运行哪些模块,但这意味着您也无法预测这些模块将需要多少内存。
  • V8 还使用 GC 堆之外的临时内存进行解析和编译。数字取决于正在运行的代码,从几千字节到千兆字节或更多(例如,对于巨大的 asm.js 代码库),一切皆有可能。这些是相对短暂的内存消耗峰值,因此一方面您可能不想限制长期堆内存来解决它们,但另一方面这意味着它们可以使您的进程达到系统限制。