2017-02-13 1150 views
3

我们在Docker容器内部运行1GB,2GB或4GB硬盘内的节点进程。每个容器通常只运行一个单独的Node进程(可能还有一个很小的shell脚本包装器)。为了这个问题的目的,我们假设Node进程永远不会分叉更多的进程。如何确定给定内存限制的节点--max_old_space_size?

对于我们较大的容器,如果我们没有设置--max_old_space_size我们自己,那么在我们使用的节点版本(在64位机器上)defaults to 1400MB。 (这将在更高版本的节点中使用change to 2048MB)。

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

我注意到,在定义kMaxOldSpaceSizeHugeMemoryDe​​vice的地方,它看起来像默认的“max semi space”是16MB,默认的“max executable size”是512MB。所以我怀疑这意味着当确定这个标志的值时,我应该从容器的内存限制中减去至少528。但肯定有其他的方式,节点使用内存? (更具体地说,我们是一个托管服务,向我们的用户销售特定大小的容器,其中大部分用于Node进程。我们希望能够告诉我们的客户需要什么标志这样它们既不会被我们的限制所杀,也不会支付我们Node的配置不允许它们实际使用的容量。)

回答

2

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

你找到控制垃圾收集堆的大小的常量,但你已经猜到了,有很多方法消耗的内存,这不是该堆的一部分:

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

当你说“节点模块”,你的意思是链接在C++代码或其他? –

+0

我的意思是本机模块。任何运行的C++(以及其他非JavaScript)代码都可以分配V8控制之外的内存。 – jmrk

相关问题