我最近遇到了一点麻烦:GenServer 进程使用的内存非常高,可能是因为大量的二进制泄漏。
问题来自于这里:我们通过 GenServer 接收大型二进制文件,并将它们传递给消费者,然后消费者与该数据进行交互。现在,这些大型二进制文件永远不会分配给变量,GC 也不会遍历它们。
我尝试在管理数据后使进程休眠,这部分起作用,因为进程使用的内存减少了很多,但由于二进制文件没有被GC,它们使用的内存量缓慢但稳定地增加,从大约 25 分钟内,不休眠时的 30 MB 到进程休眠时的 200MB。
我还尝试设置 :erlang.system_flag(:fullsweep_after, 0)
,这也有效并将进程使用的内存降低了大约 20%。
Before和 after 。 我必须说,进程时常使用的内存会减少到 60-70MB。
编辑:使用 :recon.bin_leak(15) 释放 a lot of memory -- result :recon.bin_leak(15)
无论如何,使用的内存仍然很高,我完全确定它可以修复。
Here您可以在“进程”选项卡中从观察者处获取屏幕截图。正如你所看到的,GenServer 是像 cookies 怪物一样吃内存的人。
我对这个主题进行了很多研究,尝试了那里给出的所有建议和可能的解决方案,尽管如此,我仍然处于这个位置。
欢迎任何帮助。
Code of interest这可能是导致这个+ Applications tree 。 4 个进程中有 3 个(<0.294.0>、<0.295.0>、<0.297.0> 正在使用 27MB of memory 。
预先感谢您的阅读。
最佳答案
您可以尝试将 :hibernate
原子添加到 GenStage 相关模块中的 handle_events
返回值中。例如:
def handle_events(events, _from, %{handler: handler, public: public} = state) do
public = handle(handler, events, public)
{:noreply, [], %{state | public: public}, :hibernate}
end
另一种选择是在 :recon.bin_leak()
之后记录 PID,然后将它们传递给 Process.info(PID)
以获取有关违规行为的更多信息GenServers。
一些额外的资源: https://elixirforum.com/t/extremely-high-memory-usage-in-genservers/4035/23
https://www.erlang-in-anger.com/ (特别是关于内存泄漏的第 7 章)
关于memory-leaks - GenServer 进程的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52297140/