如何确定节点–max_old_space_size给定的内存限制?

我们在Docker容器内部运行1GB,2GB或4GB硬盘内的Node进程。 每个容器通常只运行一个单独的Node进程(加上可能是一个小型的shell脚本包装器)。 为了这个问题的目的,我们假设Node进程永远不会分叉更多的进程。

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

理想情况下,我们希望我们的Node进程尽可能多地使用容器,而不会超出内存。 问题是 – 我们应该使用什么数字? 我的理解是,这个特殊的标志调整了Node使用的最大内存池的大小,但它不是唯一的池 – 例如,堆中有一个“非老”的部分,有堆栈等等。我应该从容器的大小减去设置此标志为了远离cgroup内存限制,但仍然最大限度地使用此容器中允许的内存量?

我注意到,从kMaxOldSpaceSizeHugeMemoryDe​​vice被定义的地方,它看起来像默认的“最大半空间”是16MB,默认的“最大可执行文件大小”是512MB。 所以我怀疑这意味着当确定这个标志的值时,我应该从容器的内存限制中减去至less528。 但是肯定有其他的方式,节点使用内存?

(更具体地说,我们是一个托pipe服务,向我们的用户销售特定大小的容器,其中大部分用于Node进程。我们希望能够告诉我们的客户要设置什么标志,以便他们既没有被我们的限制杀死,也没有支付我们Node的configuration不允许他们实际使用的容量。)

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

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

  • 例如,大的string和大的TypedArrays通常由embedded器(即节点及其模块,而不是V8本身)以及GC堆中的外部pipe理。
  • 通常,节点模块可以使用任何他们想要的内存。 大概你不想限制你的客户可以运行的模块,但这意味着你也不能预测这些模块需要多less内存。
  • V8还使用GC'ed堆外的临时内存进行parsing和编译。 数字取决于正在运行的代码,从几千字节到一千兆字节或更多(例如,对于巨大的asm.js代码库),任何事情都是可能的。 这些是相对短暂的内存消耗高峰,所以一方面你可能不想限制长寿命的堆内存来解决它们,但另一方面,这意味着它们可以使你的进程运行到系统限制。