两眼一抹黑

博客园 首页 联系 订阅 管理

首先使用erlang:memory()确定是哪个部分内存吃紧,根据输出的内容,比对内存占用大小,有针对性地进行分析。在erlang系统里内存的单位为word,通过erlang:system_info(wordsize)接口可以看到一个word占用多少个字节。如32位系统是4字节,64位系统是8字节。

> memory().                                     
[{total,13079568},
 {processes,4214248},
 {processes_used,4213320},
 {system,8865320},
 {atom,202481},
 {atom_used,189725},
 {binary,52800},
 {code,4618749},
 {ets,263848}]
> erlang:system_info(wordsize).
8

1.进程占用过多内存的情况(processes值较大)

可用etop查找内存占用高的进程,也可以排序所有进程(erlang:processes/0可获得所有进程pid)的内存占用(erlang:process_info(Pid, heap_size)可获得进程内存占用)。

找到目标进程后分析该进程的信息process_info(Pid)进一步发现问题,通常找到目标进程,就能从代码和进程状态中分析出问题。可能的问题有:

      是否陷入非尾递归的死循环?(如果一直吃CPU不吃内存则可能是尾递归的死循环导致)

      进程的主循环是否没用尾递归,导致调用栈无限增长?

      是否存入过多不必要的数据到进程字典中且没有及时erase?

      gen_server的state中是否存入过多内容?

etop memory示例:

> spawn(fun() -> etop:start([{sort, memory}]) end).
<0.34.0>
   
========================================================================================
 nonode@nohost                                                             11:50:35
 Load:  cpu         0               Memory:  total       12642    binary         29
        procs      28                        processes    4076    code         4454
        runq        0                        atom          198    ets           256
   
Pid            Name or Initial Func    Time    Reds  Memory    MsgQ Current Function
----------------------------------------------------------------------------------------
<0.7.0>        application_controll     '-'    7270  426440       0 gen_server:loop/6   
<0.12.0>       code_server              '-'   98774  142688       0 code_server:loop/1  
<0.26.0>       erlang:apply/2           '-'    9840  122072       0 shell:get_command1/5
<0.3.0>        erl_prim_loader          '-'  181804   62856       0 erl_prim_loader:loop
<0.23.0>       user_drv                 '-'    4122   26496       0 user_drv:server_loop
<0.0.0>        init                     '-'    2347   24520       0 init:loop/1         
<0.32.0>       erlang:apply/2           '-'    1668   21424       0 shell:eval_loop/3   
<0.11.0>       kernel_sup               '-'    1543   12152       0 gen_server:loop/6   
<0.25.0>       group:server/3           '-'    1613   11864       0 group:more_data/5   
<0.6.0>        error_logger             '-'     227    6904       0 gen_event:fetch_msg/
========================================================================================
>etop:stop().

 

2.ets表占用过多内存的情况(ets值较大)

   排序所有ets表(ets:all/0可获得所有ets表名Tab)的内存占用(ets:info(Tab, memory)可获得内存占用),找出最占内存的ets表进行分析。ets表过大,是因为insert过多内容,却很少delete。分析表的功能,寻求恰当的方式做优化,节源开流。

ets表内存战斗排序示例:

> lists:sublist(lists:reverse(lists:keysort(2,[{T, ets:info(T, memory)} || T <- ets:all()])), 10).
[{1,11220},
 {4098,7022},
 {ac_tab,942},
 {inet_db,497},
 {global_locks,302},
 {global_names,302},
 {global_names_ext,302},
 {global_pid_names,302},
 {global_pid_ids,302},
 {inet_cache,302}]

一些优化的思路:

      定期将不常用数据清理出内存

      选择更优的数据结构(如选择binary存字符串,而不是list)

      优化掉冗余的数据(如相同数据拷贝多份的情况,可以优化成只保存一份数据

 

PS:本文非权威,仅为个人思考总结

posted on 2017-01-05 20:58  两眼一抹黑  阅读(924)  评论(0编辑  收藏  举报