Elixir进程占用过多内存

时间:2019-01-09 14:52:32

标签: caching elixir phoenix-framework gen-server ets

我正在从一个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。

1 个答案:

答案 0 :(得分:6)

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

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

我如何解决此问题的方法是将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。那就是我所期望的。