为什么 Erlang / Elixir 观察者内存使用量不加起来?

Moo*_*oon 2 erlang elixir phoenix-framework

我开始使用 Elixir 并在使用 iex 连接到我的远程生产节点时观察到一些奇怪的行为。

如下面的屏幕截图所示,观察者报告总共有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
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

所以,我的第一个问题是这额外的23 MB内存来自哪里?我很确定这不仅仅是一个报告问题。因为当我查看 Kubernetes pod 的内存消耗时,它是~102 MB,这与观察者显示的数字一致。

在此处输入图片说明

我唯一能想到的是那23 MB还没有被垃圾收集。我的假设有效吗?如果是这样,自该容器启动以来已经过去了 6 个小时。而且我从一开始就一直在监视内存消耗。这不应该现在被垃圾收集吗?

第二个问题:我可以进行任何 Erlang VM / Elixir 配置调整来优化内存占用吗?

Lay*_*mer 5

我还一直在尝试解决 OTP 应用程序中有关内存管理的问题,其中一种对我特别有用的工具是 Fred Hebert 编写的名为recon的库。特别recon_alloc是提供有关 Erlang VM 中内存使用情况的非常有用信息的模块。

丢失的兆字节

以下引用直接取自该recon_alloc:memory()函数的文档,可能会让您了解正在发生的事情:

`allocated' 报告的内存应该与操作系统报告的大致相符。如果这个数量相差很大,这可能表明有人在 Erlang 自己的分配器之外直接在 C 中分配内存——一个很大的警告信号。目前有三种内存分配来源不计入此值:mseg 分配器中的缓存段、任何作为超级载体分配的内存,以及在内存分配器初始化之前在启动期间分配的小块内存。另请注意,内存使用率低可能是内存碎片的标志,在这种情况下,建议探索哪个特定的分配器有问题。

所以我认为额外的 23 MB 内存使用可能是由一些不需要的分配引起的,或者可能是由于碎片。


调整(非常谨慎 /!\ )

至于你的第二个问题,Erlang中有一个工具叫erts_alloc,里面也描述了手动配置内存分配器。可以通过将命令行标志传递给模拟器来完成,例如:

erl +SOMEFLAG +SOMEOTHERFLAG

但是文档中有一个很大的红色警告,强烈建议使用这些标志会导致比使用默认配置更糟糕的行为。

因此,如果确实是解决问题的唯一方法,那么我的建议是采用这些修改。在那种情况下,有一关于 Erlang 运行时系统的帮助我理解了某些方面,因此我也建议您事先阅读它。

注意:这里是在黑暗中疯狂拍摄,并没有直接回答您的问题,但仔细检查您的二进制文件的情况可能会很有用,因为我看到观察者报告了 13 MB。根据它们的大小(小于或大于 64 字节),它们存储在进程堆中或通过引用访问。我遇到过第 1 种情况,大量小二进制文件堆积并最终使我的系统崩溃。


在尝试解决这些问题时,我还发现了一些其他有用的资源:

[erlang:garbage_collect(Pid) || Pid <- processes()].

它将立即在所有正在运行的进程上触发 GC。就我而言,它创造了奇迹。您也可以添加一个选项来异步调用它,这样您就不必在全部完成之前阻塞:

[erlang:garbage_collect(Pid, [{async, RequestId}]) || Pid <- processes()].

希望这可以帮助 :)