Erlang記憶體占用排查流程

2021-10-03 20:41:42 字數 2734 閱讀 7966

使用erlang搭建遊戲伺服器時,運維往往會吐槽cpu占用過高、頻寬太大或者記憶體消耗太快,本文總結一下排查記憶體占用過高的主要思路和流程。

erlang:system_info(process_count).
看是否有大量的異常程序在耗記憶體,之前寫過一篇博文(點我檢視文章)記錄過乙個類似的問題:專案因為錯誤使用了三方資料庫連線池,連線程序異常重啟,產生了大量的資料庫連線耗盡mysql連線池。

[p || p<-processes(),

[,] <- [process_info(p,[links,monitors])],

==ls,==ms].

或通過

supervisor:count_children/1
檢視sup下程序數量和狀態。

erlang:memory().
輸出(單位是byte):

[,,

,,,,

,,]

需要通過靜態和動態兩個維度對記憶體進行考核:

atom不會被gc。

在編寫**時,盡量避免動態生成atom,因為一旦你的輸入源不可靠或受到攻擊(特別針對網路訊息),atom記憶體增長可能導致節點crash。

可以考慮將atom生成函式替換為更安全的版本:

list_to_atom/1 -> list_to_existing_atom/1

binary_to_atom/2 -> binary_to_existing_atom/2

binary_to_term(bin) -> binary_to_term(bin,[safe])

ets記憶體占用過高,可能是因為表過大,或者動態生成了太多的ets表。

通過

ets:i().
檢視ets表條目數,大小,占用記憶體等。

erlang binary大致上分為兩種,heap binary(<=64位元組)和refc binary(>64位元組),分別位於程序堆和全域性堆上,程序通過probin持有refc binary的引用,當refc binary引用計數為0時,被gc。

recon提供的關於binary問題檢測的函式有:

% 列印出引用的refc binary記憶體最高的n個程序

recon:proc_count(binary_memory, n)

% 對所有程序執行gc 列印出gc前後procbin個數減少數量最多的n個程序

recon:bin_leak(n)

以上兩個函式,通常可以找出有問題的程序,然後針對程序的業務邏輯和上下文進行優化。通常來說,針對於refc binary,有如下思路:

每過一段時間手動gc(高效,不優雅)

如果只持有大binary中的一小段,用binary:copy/1-2(減少refc binary引用)

將涉及大binary的工作移到臨時一次性程序中,做完工作就死亡(變相的手動gc)

對非活動程序使用hibernate呼叫(該呼叫將程序掛起,執行gc並清空調用棧,在收到訊息時再喚醒)

一種典型地binary洩露情形發生在當乙個生命週期很長的中介軟體當作控制和傳遞大型refc binary訊息的請求控制器或訊息路由器時,因為procbin僅僅只是個引用,因此它們成本很低而且在中介軟體程序中需要花很長的時間去觸發gc,所以即使除了中介軟體其他所有程序都已經gc了某個refc binary對應的procbin,該refc binary也需要保留在共享堆裡。因此中介軟體程序成為了主要的洩漏源。

針對這種情況,有如下解決方案:

避免中介軟體接觸到refc binary,由中介軟體程序返回目標程序的pid,由原始呼叫者來進行binary**

調整中介軟體程序的gc頻率(fullsweep_after)

另一部分非erlang虛擬機器管制的記憶體通常來自於第三方driver或nif,要確認是否是這部分記憶體出了問題,可通過

recon_alloc:memory(allocated).
和os所報告的記憶體占用進行對比,可以大概得到c driver或nif分配的記憶體,再根據該部分記憶體的增長情況和占用比例來判斷是否出現問題。

程序記憶體占用過高可能是因為程序數量過大或者程序占用記憶體過高,通過列印占用記憶體最高的幾個程序來檢查:

recon:proc_count(memory, 10). % 列印占用記憶體最高的10個程序

recon:proc_count(message_queue_len, 10). % 列印訊息佇列最長的10個程序

或者可以通過etop的方式:

spawn(fun() -> etop:start([, , , ]) end).
使用

etop:stop().
停止列印。

erlang:process_info(pid(0,1234,0)).  # 單位是word,64位機器*8才是byte

erlang:process_info(pid(0,1234,0), memory). # 單位是byte

erlang:garbage_collect(pid(0,1234,0)).
gc玩沒什麼變化的話,估計是**出了問題,看看是不是**用了不推薦使用的實現方式。

erlang 記憶體問題診斷:

erlang記憶體吃緊之解決思路:

Erlang 程序記憶體占用排查

注 output 指定輸出方式 interval 記憶體資訊重新整理間隔時間 lines 顯示記憶體記錄行數 sort 排序規則 上文指令基於記憶體用量倒排 引數名稱 描述dictionary 程序字典中所有的資料項 registerd name 註冊的名字 status 程序狀態 links 所有...

Linux 記憶體 占用較高問題排查

按 k 檢視 free 按兆m檢視 若伺服器沒有此命令則進行pidstat 安裝pidstat 是sysstat軟體套件的一部分,sysstat包含很多監控linux系統狀態的工具,它能夠從大多數linux發行版的軟體源中獲得。ps aux head 1 ps aux grep v pid sort...

erlang 記憶體被大量占用,跟蹤過程

第一步 檢視程序數目是否正常?erlang system info process count 第二步 檢視節點的記憶體消耗在什麼地方?erlang memory 顯示記憶體大部分消耗在程序上,由此確定是程序占用了大量記憶體 第三步 檢視哪些程序占用記憶體最高?spawn fun etop star...