hibernate使用注意事项

本文深入探讨了Erlang中的hibernate模块,包括其作用、使用方式及注意事项,尤其关注了hibernate如何在内存管理中发挥作用,并通过实例展示了trycatch堆栈与hibernate实现之间的联系。文章还详细解读了hibernate的实现原理及gen_server、proc_lib等基础设施在实际应用中的考虑周到之处。

转载:http://blog.yufeng.info/archives/1615


hibernate的作用是在进程闲的时候或者内存紧张的时候,通过重新整理进程的堆和栈内存来减少内存的消耗,同时维持进程之前的状态,但是误用会引起些问题,这里我们来展开下。

erlang:hibernate文档参考这里

erlang:hibernate(Module, Function, Args)

Types:

Module = Function = atom()
Args = [term()]
Puts the calling process into a wait state where its memory allocation has been reduced as much as possible, which is useful if the process does not expect to receive any messages in the near future.

The process will be awaken when a message is sent to it, and control will resume in Module:Function with the arguments given by Args with the call stack emptied, meaning that the process will terminate when that function returns. Thus erlang:hibernate/3 will never return to its caller.

If the process has any message in its message queue, the process will be awaken immediately in the same way as described above.

In more technical terms, what erlang:hibernate/3 does is the following. It discards the call stack for the process. Then it garbage collects the process. After the garbage collection, all live data is in one continuous heap. The heap is then shrunken to the exact same size as the live data which it holds (even if that size is less than the minimum heap size for the process).

If the size of the live data in the process is less than the minimum heap size, the first garbage collection occurring after the process has been awaken will ensure that the heap size is changed to a size not smaller than the minimum heap size.

Note that emptying the call stack means that any surrounding catch is removed and has to be re-inserted after hibernation. One effect of this is that processes started using proc_lib (also indirectly, such as gen_server processes), should use proc_lib:hibernate/3 instead to ensure that the exception handler continues to work when the process wakes up.

请注意最后最后一句话, 由于hibernate把堆栈全部清掉了,在wakeup的时候,如果之前有try catch需要重新构建, 这就是proc_lib考虑周到的地方。
首先我们先看下try catch堆栈的情况,看例子:

$ cat try_stack.erl
-module(try_stack).
-compile(export_all).
 
loop()->
    receive _-> loop() end.
     
x()->
    register(x, self()),
    loop().
 
y()->
    register(y, self()),
    try
    loop()
    catch
    _:_ ->ok
    end.
 
start()->
    spawn(fun x/0),
    spawn(fun y/0),
    ok.
     
$ erlc try_stack.erl
$ erl -s try_stack
Erlang (BEAM) emulator version 5.6.5 1 [async-threads:0] [hipe] [kernel-poll:false]
 
Eshell V5.6.5  (abort with ^G)
1>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
A

按下大写的A, 产生crashdump文件,用CrashDumpViewer看到进程的堆栈情况,可以看到下图:

从图中我们知道,try catch 是往堆栈里面都压入了出错时候的返回地址,而普通的函数没有压入任何东西。

确认了这个问题,就很容易理解proc_lib:hibernate的实现了,我们看代码:

%% proc_lib.erl:L192
 
hibernate(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
    erlang:hibernate(?MODULE, wake_up, [M, F, A]).
 
wake_up(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
    try
           apply(M, F, A)
    catch
        Class:Reason ->
            exit_p(Class, Reason)
    end.

总结:标准库的东西总是会考虑比较周到,我们尽量多用gen_server,proc_lib这样的基础设施。
祝玩得开心!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值