ERlang堆溢出
我有一个很好的计划 差不多完成了 然而,在运行大约12小时后,我看到堆崩溃 我记得听说,如果在递归堆栈构建时不能以某种方式编程erlang,那么就不能进行编程。有人能举个例子吗 还有,有没有办法对“正在堆积的”过程进行实时监控 问候 编辑-怎么办ERlang堆溢出,erlang,heap,overflow,Erlang,Heap,Overflow,我有一个很好的计划 差不多完成了 然而,在运行大约12小时后,我看到堆崩溃 我记得听说,如果在递归堆栈构建时不能以某种方式编程erlang,那么就不能进行编程。有人能举个例子吗 还有,有没有办法对“正在堆积的”过程进行实时监控 问候 编辑-怎么办 loop() -> receive {sys, Msg} -> handle_sys_msg(Msg), loop(); {From, Msg} ->
loop() ->
receive
{sys, Msg} ->
handle_sys_msg(Msg),
loop();
{From, Msg} ->
Reply = handle_msg(Msg),
From ! Reply,
loop();
_ -> continue
end,
loop().
流程循环必须是尾部递归的 不要
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", []).
请参阅:流程循环必须是尾部递归的 不要
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", []).
请参阅:类似的内容可用于监视系统中进程的当前堆使用情况。只需将其放入循环gen_服务器的打印输出中,或者每隔一段时间在shell中运行一次
lists:reverse(lists:keysort(2,
[{Pid,catch element(2,process_info(Pid,total_heap_size))} || Pid <- processes()])).
列表:反向(列表:按键端口(2,
[{Pid,catch元素(2,process_info(Pid,total_heap_size))}| | Pid类似的内容可用于监视系统中进程的当前堆使用情况。只需将其放在循环gen_服务器的打印输出中,或者每隔一段时间在shell中运行一次
lists:reverse(lists:keysort(2,
[{Pid,catch element(2,process_info(Pid,total_heap_size))} || Pid <- processes()])).
列表:反向(列表:按键端口(2,
[{Pid,catch元素(2,process_info(Pid,total_heap_size))}| | Pid即使您的编辑不是尾部递归的:
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,{u}
消息,将从receive内部调用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()
实际上总是函数中最后要做的事情。即使您的编辑也不是尾部递归的:
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,{u}
消息,将从receive内部调用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().
或
其中调用循环()
实际上总是函数中最后要做的事情。您的编辑是尾部递归的,这意味着它不会在堆栈上构建任何内容。正如@Terrary ADVICE非常正确地指出,您的编辑不是尾部递归的,您的编辑是尾部递归的,这意味着它不会在堆栈上构建任何内容。如@Terrary ADVICE very正确地指出,您的编辑不是尾部递归的。如果接收在try-catch的“try”段中,该怎么办?如果出现异常,VM是否仍存储返回点?(这没有意义,因为异常将在嵌套的“try”段中捕获)是的。在try…catch
的情况下,如果表达式发生在两者之间,VM将存储堆栈帧,而不是尾部递归。在这种情况下,请使用:try Res的risk_thing()->recursive_call()catch…end
,这将防止此问题。如果接收处于“try”状态,该怎么办try-catch段?如果出现异常,VM是否仍存储返回点?(这没有意义,因为异常将在嵌套的“try”中捕获)是的。在try…catch
的情况下,如果表达式发生在两者之间,VM将存储堆栈帧,而不是尾部递归。在这种情况下,使用:try Res的risk_thing()->recursive_call()catch…end
,这将防止此问题