Elixir 进程占用内存过多

Elixir process taking up too much memory

我正在从 csv 文件中读取邮政编码,获取该数据并使用 ets 对其进行缓存。

邮政编码文件非常大 (95MB),因为它包含大约 180 万个条目。

我目前只缓存查询所需的邮政编码(大约 200k),因此存储在 ets 中的数据量应该不是问题。然而无论插入ets的次数多少,进程占用的内存量几乎没有变化。我插入 1 行或全部 180 万似乎都没有关系。

# not logging all functions defs so it is not too long.
# Comment if more into is needed.
defmodule PostcodeCache do
  use GenServer

  def cache_postcodes do
    "path_to_postcode.csv"
    |> File.read!()
    |> function_to_parse()
    |> function_to_filter()
    |> function_to_format()
    |> Enum.map(&(:ets.insert_new(:cache, &1)))
  end
end

我在终端中 运行 使用 iex -S mix 和 运行 命令 :observer.start。当我转到进程选项卡时,我的 postcodeCache 内存很大(超过 600MB)

即使我过滤了文件,所以我最终只在 :ets 中存储了 1 个邮政编码,它仍然超过 600MB。

我意识到我犯的错误是当我查看进程的内存并假设它与缓存有关时。

因为这是一个 GenServer,它在读取 csv 文件时保留了所有信息 (File.read!),而且似乎还保留了对该文件所做的所有更改。

我是如何解决这个问题的,方法是将 File.read! 更改为 File.stream!。然后我使用 Enum.each 而不是映射返回的数据。

在每一个中我检查邮政编码是我想要的,如果是我然后将它插入 ets。

def cache_postcodes do
  "path_to_postcode.csv"
  |> File.stream!()
  |> Enum.each(fn(line) ->
    value_to_store = some_check_on_line(line)
    :ets.insert_new(:cache, &1)
  end)
end

通过这种方法,我的进程内存现在只有大约 2MB(不是 632MB),而我的 ets 内存大约是 30MB。这就是我所期望的。