defmodule Debug.Process do def top_memory_by_type(count \\ 5) do Process.list() |> Enum.map(&type_and_memory/1) |> Enum.reject(&is_nil/1) |> Enum.group_by(& &1.type, & &1.memory) |> Enum.map(fn {type, memory} -> %{type: type, memory: Enum.sum(memory)} end) |> Enum.sort_by(&(-&1.memory)) |> Enum.take(count) end defp type_and_memory(pid) do with [memory: memory] <- Process.info(pid, [:memory]), type when type != :dead <- type(pid) do %{type: type, memory: memory} end end def type(pid) do with :error <- process_type_if_dead(pid), :error <- process_label(pid), :error <- initial_module(pid) do :unknown end end defp process_type_if_dead(pid) do if Process.alive?(pid) do :error else :dead end end defp process_label(pid) do case :proc_lib.get_label(pid) do :undefined -> :error {name, _} -> name {name, _, _} -> name name when is_atom(name) -> name name when is_binary(name) -> name _ -> :error end end defp initial_module(pid) do [dictionary: dictionary] = Process.info(pid, [:dictionary]) dictionary |> Map.new() |> Map.get(:"$initial_call") |> case do {module, _function, _arg_count} -> module _ -> initial_module_from_info(pid) end end defp initial_module_from_info(pid) do case Process.info(pid, [:initial_call]) do [initial_call: {module, _function, _arg_count}] -> module nil -> :error end end end