Erlang 应用程序中观察到的内存泄漏
让我简单地提出我的问题如下。我的是一个用 erlang 构建的网络路由器软件,但在特定场景下,我观察到 VM 所示的内存增长非常高。
我有一个进程从套接字接收来自其他进程的二进制数据包。
这个过程,解析二进制数据包并将二进制数据包传递给gen_server(调用handle_cast)
gen_server 再次在 ETS 表中存储一些信息并将数据包发送到对等服务器。
当对等服务器响应时,ETS 中的条目将被删除,并且 gen_server 响应第一个进程
Also if the first process (which sent packet to gen_server) gets timedout after 5 seconds waiting for response from gen_server , it also deletes the ETS entry in the gen_server and exits.现在,当许多事件超时(由于对等服务器不可用)时,我观察到内存的高增长,并且根据我的研究,它是 erlang:memory 给出的“**binary**”和“**processes_used**”该命令占用了大部分内存。
但当事件处理成功时情况并非如此。
Let me put my question as simple as below. Mine is a network router software built in erlang, but at a particular scenario I am observing very high memory growth as shown by VM.
I have one process which receives binary packet from some other process from socket.
This process, parses the binary packet and passes the binary packet to a gen_server (handle_cast is called)
The gen_server again stores some information in ETS table and send the packet to the peer server.
When the peer server responds back the entry from the ETS is deleted and the gen_server responds back to the first process
Also if the first process (which sent packet to gen_server) gets timedout after 5 seconds waiting for response from gen_server , it also deletes the ETS entry in the gen_server and exits.
Now I am observing high memory growth when lots of events gets timed out (due to unavailability of peer server) and from what i have researched its the "**binary**" and "**processes_used**" given by erlang:memory command thats using most of the memory.
but the same is not true when events are processed successfully.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
内存丢失基本上只发生在三个地方:
你的 gen_server 的状态
你的进程邮箱
确保有某种方法可以在正常的
receive
saAny -> 中始终排出不匹配的消息(对于 gen_server
子句。handle_info
回调)。如果邮箱只是暂时填满,可能是因为接收过程对于生成消息的速度来说太慢了。这通常是异步通信的问题。如果它只是暂时的爆发,不会破坏任何东西,这可能是有意的。
在这种情况下,您可以优化接收流程
或修复您的协议以使用更少的消息
如果您有多个接收某些消息的函数,请确保定期调用所有接收部分。不要忘记
Any ->
子句。请注意,当您在 gen_servers 回调中处理时,不会收到任何消息,因此,如果您在回调中需要更多时间,则必要的异步消息可能会堆积起来(例如随机消息到达 + 固定处理时间)构建一个无限增长的队列,详细信息请参阅排队理论
在您的 ETS 表中
The memory lost can be basically only in three places:
The state of your gen_server
Your processes mailboxes
see to it that there is some way to always drain unmatched messages (for gen_server
handle_info
callback) in normalreceive
s aAny ->
clause.if the mailbox only fills up temporarily its probably because of the receiving process being too slow for the rate of messages produced. This is usually a problem for asynchronous communication. If its only temporary bursts that don't break anything this could be intended.
In this case you can either optimize the receiving process
or fix your protocol to use fewer messages
if you have multiple functions that receive some messages, make sure all receiving parts are being called regularly. Dont forget the
Any ->
clauses.Be aware that while you are processing in a gen_servers callback no messages will be received, so if you need more time in a callback that would be necessary asyncronous messages might pile up (e.g. random message arrival + fixed processing time builds a unbounded growing queue, for details see Queueing theory
In your ETS table
手动触发 GC,看看内存会发生什么情况。
trigger GC by hand and see what happens with memory.
最有可能的是,您正在运行引用二进制文件的进程。如果进程死亡,与该进程相关的所有内存都将被清除(包括仅属于该进程的任何二进制文件)。
如果您仍然有泄漏的二进制文件,则意味着您有一些长时间运行的进程(服务器、单例等),它们在其进程状态或通过非尾递归函数保留对二进制文件的引用。确保一旦进程通信超时或终止,就清理你的状态。另外,请检查是否未使用非尾递归调用在堆上留下对二进制文件的引用。
Most likely you're leaving processes running that has references to binaries. If a process dies, all memory related to that process will be cleaned up (including any binaries that only belonged to that process).
If you still have leaking binaries, it means you have some long running process (server, singleton etc) that keeps references to binaries, either in its process state or by non-tail recursive functions. Make sure you clean up your state once process communication times out or they die. Also, check that you don't leave references to binaries on the heap by using non-tail recursive calls.