ERlang 堆溢出

Posted

技术标签:

【中文标题】ERlang 堆溢出【英文标题】:ERlang HEAP overflow 【发布时间】:2011-05-12 02:15:13 【问题描述】:

我有一个程序..

差不多完成了..

但是我在运行大约 12 小时后看到堆崩溃。

我记得听说你不能以某种方式对 erlang 进行编程,如果不是在你递归堆栈建立时。谁能举个例子吗?

还有什么方法可以实时监控正在堆积的进程?

问候

编辑 - 怎么样

loop() -> 
  receive
     sys, Msg ->
         handle_sys_msg(Msg),
         loop();
     From, Msg ->
          Reply = handle_msg(Msg),
          From ! Reply,
          loop();

     _ -> continue
  end,
  loop().

【问题讨论】:

您的编辑是尾递归的,这意味着它不会在堆栈上构建任何东西。 正如@TERRIBLE ADVICE 非常正确地指出您的编辑不是尾递归 【参考方案1】:

即使你的编辑不是尾递归:

loop() -> 
  receive
     sys, Msg ->
         handle_sys_msg(Msg),
         loop();
     From, Msg ->
          Reply = handle_msg(Msg),
          From ! Reply,
          loop();
      _ -> continue 
  end,
  loop().

一个函数的执行顺序是:receive ... end, loop()。现在,如果您收到sys, _ 消息,将从接收中调用loop/0,将上面的执行顺序转换为等效于:

 loop() ->
      receive
          loop() ->
               receive
                  ...
               end,
               loop(),
      end,
      loop() ->
         ...

问题在于,如果您从接收中调用loop(),VM 仍然必须存储返回点才能在receive 之后运行loop()

要使函数尾递归,您需要执行以下任一操作:

loop() -> 
  receive
     sys, Msg ->
         handle_sys_msg(Msg);
     From, Msg ->
          Reply = handle_msg(Msg),
          From ! Reply;
      _ -> continue 
  end,
  loop().

loop() -> 
  receive
     sys, Msg ->
         handle_sys_msg(Msg),
         loop();
     From, Msg ->
          Reply = handle_msg(Msg),
          From ! Reply,
          loop();
      _ -> loop()
  end.

调用loop() 确实是总是函数中要做的最后一件事。

【讨论】:

如果接收在 try-catch 的“try”段中怎么办?如果出现异常,VM 是否仍会存储返回点? (这没有意义,因为异常会在嵌套的“try”中捕获 是的。在try ... catch 的情况下,如果表达式发生在两者之间,VM 将存储一个堆栈帧而不是尾递归。在这种情况下使用:try risky_thing() of Res -> recursive_call() catch ... end 这将防止此问题【参考方案2】:

这样的东西可以用来监控系统中进程的当前堆使用情况。只需将它放在循环 gen_server 中的打印输出中,或者每隔一段时间在 shell 中运行它。

lists:reverse(lists:keysort(2,
   [Pid,catch element(2,process_info(Pid,total_heap_size)) || Pid <- processes()])).

【讨论】:

【参考方案3】:

进程循环必须是尾递归的。

不要

loop() -> 
  receive
     sys, Msg ->
         handle_sys_msg(Msg),
         loop();
     From, Msg ->
          Reply = handle_msg(Msg),
          From ! Reply,
          loop()
  end,
  io:format("Message is processed~n", []).

见:http://www.erlang.org/doc/efficiency_guide/processes.html

【讨论】:

以上是关于ERlang 堆溢出的主要内容,如果未能解决你的问题,请参考以下文章

JVM内存溢出分析:堆内存溢出+虚拟机+方法区——JVM系列

第二章:Java堆内存溢出

软件安全实验——pre6(整数溢出堆溢出栈溢出漏洞预习)

Java JVM:内存溢出(栈溢出,堆溢出,持久代溢出以及 nable to create native thread)

Linux 堆溢出原理分析

Linux 堆溢出原理分析