Erlang垃圾回收

3

我需要你在调查Erlang内存消耗问题中提供帮助。多典型的问题,是吧?

我们有两种不同的部署方案。

  • 在第一种方案中,我们在小型虚拟机(在Amazon AWS上)上运行许多相同的节点,每台机器一个节点。每台机器有4GB的RAM。
  • 在另一种部署方案中,我们在大型裸机(具有64GB的RAM)上运行这些节点,每个机器有许多节点。在这种部署中,节点被隔离在docker容器中(内存限制设置为4GB)。

我注意到,docker化节点中的进程堆比非docker化节点中相同负载的堆占用了多达3倍的RAM。我怀疑非docker化节点中的垃圾收集更积极。不幸的是,我没有任何垃圾收集统计信息,但我想尽快获得它。

要提供更多信息,我应该说我们在Ubuntu 14.04上使用HiPE R17.1和默认内核。在两种方案中,我们每个节点运行8个调度器,并使用默认的fullsweep_after标志。

我的盲猜测是Erlang默认的垃圾收集(以某种方式)依赖于/proc/meminfo(在docker化环境中不是实际的)。我不是C语言专家,也不熟悉模拟器内部,那么有没有人能指导我查看Erlang源代码中负责垃圾收集的地方以及一些模拟器选项,我可以使用这些选项来调整此行为?


Erlang社区在这个网站上相对较少(但那些了解内部情况的人确实非常了解内部情况)。你可能还想将此内容发布到邮件列表中;那里有很多人非常了解内部情况。 - zxq9
另外,请告诉我您是如何获取内存消耗数据的。如果是从像top或/proc/meminfo这样的操作系统实用程序中获取的,则您看到的原因可能与从erlang:memory/0获取内存数据时非常不同。 - zxq9
我正在使用一些不同的方式直接在Erlang节点上收集统计信息。特别是,我使用erlang:memory/0,发现erlang:memory(processes)异常。此外,我还对某些监督程序下进程的堆栈进行统计(通过对每个监督程序下的进程使用erlang:process_info(Pid,total_heap_size)获得)。 - Viacheslav Kovalev
2个回答

3
很不幸,虚拟机经常试图更加智能地管理内存,而这并不总是适用于Erlang内存管理模型。Erlang倾向于分配和释放大量小块的内存,这与通常只分配和释放少量大块内存的正常应用程序非常不同。
其中一种技术是“透明大页面”(THP),有些操作系统默认启用它,这会导致在此类虚拟机中运行的Erlang节点增长(直到崩溃)。

https://access.redhat.com/solutions/46111

https://www.digitalocean.com/company/blog/transparent-huge-pages-and-alternative-memory-allocators/

https://docs.mongodb.org/manual/tutorial/transparent-huge-pages/

因此,确保关闭THP是您可以检查的第一件事。

另一个方法是尝试调整启动Erlang VM时使用的内存选项,例如参见这篇文章:

Erlang: discrepancy of memory usage figures

对我们起作用的选项如下:

-MBas aobf -MBlmbcs 512 -MEas aobf -MElmbcs 512

关于内存分配器的更多理论:

http://www.erlang-factory.com/static/upload/media/139454517145429lukaslarsson.pdf

以下是有关内存分配器标志的更详细描述:

http://erlang.org/doc/man/erts_alloc.html


我不确定THP或HugePages如何与Erlang VM内存消耗模型交互。有什么想法吗? - jj1bdx
这是一个很好的问题,可以在Erlang邮件列表中之一进行讨论 https://www.erlang.org/community/mailinglists - Greg

1
首先要知道的是,Erlang中的垃圾回收是基于进程的。每个进程都在自己的时间内进行GC,而且相互独立。因此,您系统中的垃圾回收仅依赖于进程中的数据,而不是操作系统本身。
话虽如此,从Eralang的角度和系统的角度来看,内存消耗可能会有一些差异。因此,比较erlang:memory和系统显示的内容总是一个好主意(它可以显示一些二进制泄漏或其他内存问题)。
如果您想更深入地了解Erlang内部,请参考这两个讲座:

https://www.youtube.com/watch?v=QbzH0L_0pxI

https://www.youtube.com/watch?v=YuPaX11vZyI

如果您想更好地进行内存管理调试,我建议从http://ferd.github.io/recon/开始。


1
谢谢提供的链接!我已经尽可能地使用了recon。我对erlang:memory/0所说的内容以及我在主机上看到的内容有很好的统计数据。此外,我已经搜索了二进制泄漏,但是二进制利用并没有让我感到痛苦。只有一件奇怪的事情 - 异常的erlang进程堆使用情况(如在erlang:memory(processes)erlang:process_info(total_heap_size)中看到)。 - Viacheslav Kovalev
1
你不应该使用 erlang:memory(processes_used) 来与实际进程堆大小进行比较吗? - mpm
啊,是的。我忘记了。erlang:memory(processes)代表分配的内存,而erlang:memory(processes_used)代表实际使用的内存,我说得对吗?此外,我还有每个Erlang分配器(包括eheap_alloc)的单独统计数据。所有这些指标(processes、processes_used和eheap_alloc)几乎相同(每GB加减几兆字节)。 - Viacheslav Kovalev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接