第一步:
檢視程序數目是否正常? erlang:system_info(process_count).
第二步:
檢視節點的記憶體消耗在什麼地方?
> erlang:memory(). [,,
,,,,
,,]顯示記憶體大部分消耗在程序上,由此確定是程序占用了大量記憶體
第三步:
檢視哪些程序占用記憶體最高?
> spawn(fun() -> etop:start([, , , ]) end).
(以輸出text方式啟動etop,其間隔為1秒,輸出行數為20行,按照記憶體排序. 這裡spawn乙個新程序,目的是輸出etop資料時不影響erlang shell 輸入.)
其中」 ,」 表示占用記憶體為 12358050 words(32位系統word size為4,64位系統word size為8, 可以通過erlang:system_info(wordsize) 檢視),在64位系統下將近100m, 太誇張了!
第五步:
手動gc**,希望問題可以解決
> erlang:garbage_collect(pid(0,12571,0)).
true
再次檢視程序記憶體,發現沒有任何變化!gc沒有**到任何資源,因此消耗的記憶體還在發揮作用,沒有**!
第六步:
不要懷疑系統,首先要懷疑自己的**
認真觀察**,其大致結構如下:
send_msg(socket, pid) ->
tryreceive
->
... ->
...catch
_:_ ->
send_msg(sock, pid)
end.
其目的是迴圈等待資料,然後進行傳送,其使用了try...catch捕獲異常.
這段**有問題麼?
對,這段**的確有問題, 其不是尾遞迴! try...catch會在stack中儲存相應的資訊,異常捕獲需要放置在函式內部,所以send_msg最後呼叫的是try...catch,而不是自身,所以不是尾遞迴!
可以通過**得到驗證:
cat test.erl
-module(test).
-compile([export_all]).
t1() ->
pid = spawn(fun() -> do_t1() end),
send_msg(pid, 100000).
t2() ->
pid = spawn(fun() -> do_t2() end),
send_msg(pid, 100000).
send_msg(_pid, 0) ->
ok;send_msg(pid, n) ->
pid ! <<2:(n)>>,
timer:sleep(200),
send_msg(pid, n-1).
do_t1() ->
erlang:garbage_collect(self()),
result = erlang:process_info(self(), [memory, garbage_collection]),
io:format("~w ~n", [result]),
io:format("backtrace:~w~n~n", [erlang:process_display(self(), backtrace)]),
tryreceive
_ ->
do_t1()
endcatch
_:_ ->
do_t1()
end.
do_t2() ->
erlang:garbage_collect(self()),
result = erlang:process_info(self(), [memory, garbage_collection]),
io:format("~w ~n", [result]),
io:format("backtrace:~w~n~n", [erlang:process_display(self(), backtrace)]),
receive
_ ->
do_t2()
end.
版本1:erlc test.erl && erl -eval "test:t1()"
版本2:erlc test.erl && erl -eval "test:t2()"
你會看到版本1**的呼叫堆疊在不斷增長,記憶體也在增長, 而版本2函式呼叫位址保持不變,記憶體也沒有發生變化!
總結:1,伺服器程式設計中,迴圈一定確保為尾遞迴
2,善於使用otp,如果使用gen_server替換手寫loop,就不會出現這個問題!
Erlang記憶體占用排查流程
使用erlang搭建遊戲伺服器時,運維往往會吐槽cpu占用過高 頻寬太大或者記憶體消耗太快,本文總結一下排查記憶體占用過高的主要思路和流程。erlang system info process count 看是否有大量的異常程序在耗記憶體,之前寫過一篇博文 點我檢視文章 記錄過乙個類似的問題 專案因...
Erlang 程序記憶體占用排查
注 output 指定輸出方式 interval 記憶體資訊重新整理間隔時間 lines 顯示記憶體記錄行數 sort 排序規則 上文指令基於記憶體用量倒排 引數名稱 描述dictionary 程序字典中所有的資料項 registerd name 註冊的名字 status 程序狀態 links 所有...
PHP查詢MySQL大量資料的記憶體占用分析
from 這篇文章主要是從原理,手冊和原始碼分析在php中查詢mysql返回大量結果時,記憶體占用的問題,同時對使用mysql c api也有涉及.昨天,有同事在php討論群裡提到,他做的乙個專案由於mysql查詢返回的結果太多 達10萬條 從而導致php記憶體不夠用.所以,他問,在執行下面的 遍歷...