调查使用binary最多TOPN进程
原创文章,转载请注明: 转载自系统技术非业余研究
本文链接地址: 调查使用binary最多TOPN进程
Erlang程序是非常健壮的,通常一个典型的虚拟机里面跑很多进程,这些进程即使有bug,按照erlang的哲学是快速死掉,系统留下异常堆栈,很容易发现问题。照理说erlang是很少crash的,但实际情况不是这样的。
在erlang VM crash的案例中,我们会发现大部分的网络服务器的原因都是binary内存不够申请不出来,所以内存短缺是最致命的影响稳定的因素。通常设计良好的erlang程序,按照otp的设计哲学不会占用太多内存的,即使占用了gc也很快就会回收的,除了binary这个内存使用大户。
比如说网络服务器程序,我们用binary来保存用户的封包,我们无法预测用户要发送多大的包,比如上限是50M,如果我们的系统有1000个这样的用户,在极端情况下,我们是要耗用50G内存的。通常在这种情况下,我们拿不出这么多物理内存,然后crash就很大概率会发生。
调查哪些进程用掉了最多的binary内存就很有必要了,我们在极端情况下,可以选择性的杀掉这些内存,保护自己不至于毁灭。
erlang:process_info有个未公开的选项 binary用来获取这个进程拥有的binary情况。
我们看下它的实现:
static Eterm bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh) { struct erl_off_heap_header* ohh; Eterm res = NIL; Eterm tuple; for (ohh = oh->first; ohh; ohh = ohh->next) { if (ohh->thing_word == HEADER_PROC_BIN) { ProcBin* pb = (ProcBin*) ohh; Eterm val = erts_bld_uword(hpp, szp, (UWord) pb->val); Eterm orig_size = erts_bld_uint(hpp, szp, pb->val->orig_size); if (szp) *szp += 4+2; if (hpp) { Uint refc = (Uint) erts_smp_atomic_read_nob(&pb->val->refc); tuple = TUPLE3(*hpp, val, orig_size, make_small(refc)); res = CONS(*hpp + 4, tuple, res); *hpp += 4+2; } } } return res; } Eterm process_info_aux(Process *BIF_P, Process *rp, Eterm rpid, Eterm item, int always_wrap) { ... case am_binary: { Uint sz = 3; (void) bld_bin_list(NULL, &sz, &MSO(rp)); hp = HAlloc(BIF_P, sz); res = bld_bin_list(&hp, NULL, &MSO(rp)); break; } ... }
这个选项会返回一个bin情况tuple的列表,每个tuple的第一个是binary的地址,第二个是大小,第三个是引用次数。
我们来演示下如何使用:
$ erl Erlang R15B02 (erts-5.9.2) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.9.2 (abort with ^G) 1> X= <<0:1024>>. <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,...>> 2> Y= <<0:2048>>. <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,...>> 3> Z= <<0:256>>. <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,...>> 4> erlang:process_info(self(), binary). {binary,[{140379060495896,128,5}, {140379060500136,256,4}, {140379060500896,32,3}]} 5>
三个binary信息和我们预想的是符合的。
最后我们用这个选项来做个更智能的,调查使用binary最多TOPN进程,代码如下:
topN(N)-> [{M, P, process_info(P, [registered_name, initial_call,current_function, dictionary]), B} || {P, M, B} <- lists:sublist(lists:reverse(lists:keysort(2,processes_sorted_by_binary())),N)]. processes_sorted_by_binary()-> [case process_info(P, binary) of {_, Bins} -> SortedBins = lists:usort(Bins), {_, Sizes, _} = lists:unzip3(SortedBins), {P, lists:sum(Sizes), []}; _ -> {P, 0, []} end ||P <- processes()].
没事调用下,查查谁在消耗binary内存,有助于发现问题。
祝玩得开心!
Post Footer automatically generated by wp-posturl plugin for wordpress.
Recent Comments