要從一次線上的內存泄漏提及. 最終定位到在異步send方法中, monitor了被調用進程, 而又沒有釋放, 致使泄漏. 違反直覺的是, 這個泄漏是雙向的, A monitor B後, A會記錄 monitors B, B會記錄 monitored_by A. 進程A退出後, 進程B不會釋放 monitored_by A. 因此, 在使用monitor時, 注意在任何狀況下, 都要demonitor.html
monitor 佔用的內存被統計爲 system/process, 屬於std_alloc分配器.
能夠用process內存排序, 找出泄漏的進程.git
:recon.proc_count(:memory, 10)
接着, 能夠用process_info, 查看可疑的進程. monitors是monitors的進程, monitored_by是被哪些進程monitor.程序員
iex(xxxx@xxxx.)51> {_, b} = :erlang.process_info(pid(0,3182,0), :monitors) {:monitors, [#PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>, #PID<55192.4940.0>,
此外, 還能夠用allocated_types, :erlang.memory, 看到system, std_alloc有大量泄漏.github
iex(xxxx@xxxx.)35> :recon_alloc.memory(:allocated_types) [ binary_alloc: 7634944, driver_alloc: 6324224, eheap_alloc: 58241024, ets_alloc: 10780672, fix_alloc: 4751360, ll_alloc: 96993280, sl_alloc: 557056, std_alloc: 830242816, temp_alloc: 2228224 ] iex(xxxx@xxxx.)4> :erlang.memory [ total: 28235126584, processes: 441032432, processes_used: 440339304, system: 27794094152, atom: 1982841, atom_used: 1971208, binary: 15334152, code: 46042580, ets: 28443288 ]
若是懷疑monitor有泄漏, 能夠直接根據monitors/monitored_by列表長度排序:異步
Enum.map(:erlang.processes(), fn proc -> {:erlang.process_info(proc, :monitors), proc} end) |> Enum.filter(fn v -> elem(v, 0) != :undefined end) |> Enum.map(fn v -> {length(elem(elem(v, 0), 1)), elem(v, 1)} end) |> Enum.sort(fn({a, _}, {b, _}) -> a > b end) |> Enum.take(100) Enum.map(:erlang.processes(), fn proc -> {:erlang.process_info(proc, :monitored_by), proc} end) |> Enum.filter(fn v -> elem(v, 0) != :undefined end) |> Enum.map(fn v -> {length(elem(elem(v, 0), 1)), elem(v, 1)} end) |> Enum.sort(fn({a, _}, {b, _}) -> a > b end) |> Enum.take(100)
顯然 A monitor B, 雙方都要記錄, 不然atom
進程A退出時, 必然要通知全部被monitor的進程釋放這塊內存. 我的認爲在語言層面實現會更好. erlang沒作這點, 只要程序員確保必定demonitor. 就沒有問題.
在節點連接斷開時, monitored_by的內存是會被釋放的. 假如erlang連這點都沒能保證, 不管如何都沒法實現正確了.code
https://erlang.org/doc/man/er...
https://ferd.github.io/recon/...htm