当我使用iex连接到我的远程生产节点时,我开始使用Elixir并观察一些奇怪的行为。
如下面的屏幕截图所示,观察者报告正在使用总计 92 MB 内存。但是,当你总结进程,原子,二进制文件,代码和ets的内存消耗时,它会出现: ~69 MB
Processes 19.00 MB
Atoms 0.97 MB (969 kB)
Binaries 13.00 MB
Code 28.00 MB
ETS 7.69 MB (7685 kB)
-------------------
Total 68.66 MB
所以,我的第一个问题是这个额外的 23 MB 内存来自哪里?我很确定这不仅仅是一个报道问题。因为当我查看我的Kubernetes pod的内存消耗时,它是 ~102 MB ,这与观察者显示的数字一致。
我唯一能想到的是那些 23 MB 尚未被垃圾收集。我的假设有效吗?如果是这样,自该容器启动以来已经过了6个小时。我一直在监视内存消耗。难道现在这不是垃圾收集吗?
第二个问题:我是否有任何可以优化内存占用的Erlang VM / Elixir配置调整?
答案 0 :(得分:3)
我也一直在尝试解决有关OTP应用程序中的内存管理的问题,其中一个对我特别有用的工具是Fred Hebert编写的名为recon的库。尤其是recon_alloc
模块,它提供了有关Erlang VM中内存使用情况的非常有用的信息。
以下引文直接摘自recon_alloc:memory()
函数的文档,可能使您对正在发生的事情有深刻的了解:
由“已分配”报告的内存应与操作系统大致匹配 报告。如果该金额相差很大,则可能是 表示有人在C之外直接在C中分配内存 Erlang自己的分配器-一个很大的警告信号。目前有 不计入此的三个内存分配源 值:mseg分配器中的缓存段,已分配的任何内存 作为超级载体,并在 在初始化内存分配器之前启动。另请注意 内存使用率低可能是内存碎片的迹象,其中 建议找出一个具体的分配器有问题的案例。
因此,我认为额外的23 MB内存使用量可能是由于某些不必要的分配所致,或者可能是由于碎片所致。
关于第二个问题,Erlang中有一个名为erts_alloc的工具,该工具还描述了内存分配器的手动配置。可以通过将命令行标志传递给仿真器来完成,例如:
erl +SOMEFLAG +SOMEOTHERFLAG
但是文档中有一个大的红色警告,强烈表明与默认配置相比,弄乱这些标志可能导致更糟糕的行为。
因此,我的建议是,如果确实是解决问题的唯一方法,请采用这些修改。在这种情况下,关于Erlang运行时系统的问题book可以帮助我理解某些方面,因此我还建议您事先对其进行阅读。
注意:此处在黑暗中狂野射击,无法直接回答您的问题,但仔细检查二进制文件的状态可能很有用,因为我发现已报告了13 MB由观察者。根据它们的大小(小于或大于64字节),它们被存储在进程堆中或通过引用进行访问。我遇到了第一种情况,其中堆满了许多小二进制文件,最终导致系统崩溃。
在尝试解决这些问题时,我发现了一些其他有用的资源:
[erlang:garbage_collect(Pid) || Pid <- processes()].
它将立即在所有正在运行的进程上触发GC。就我而言,它创造了奇迹。您也可以添加一个选项以异步方式调用它,这样就不必在所有操作完成后进行阻塞:
[erlang:garbage_collect(Pid, [{async, RequestId}]) || Pid <- processes()].
希望这会有所帮助:)