Elixir 使用xmerl读取大型XML文件会使节点崩溃

Elixir 使用xmerl读取大型XML文件会使节点崩溃,elixir,Elixir,我有以下代码可以读取wikipedia转储文件(~50 GB)并根据请求交付页面: defmodule Pages do def start_link(filename) do pid = spawn_link(__MODULE__, :loop, [filename]) Process.register(pid, :pages) pid end def next(xml_parser) do send(xml_parser, {:get_next,

我有以下代码可以读取wikipedia转储文件(~50 GB)并根据请求交付页面:

defmodule Pages do
  def start_link(filename) do
    pid = spawn_link(__MODULE__, :loop, [filename])
    Process.register(pid, :pages)
    pid
  end

  def next(xml_parser) do
    send(xml_parser, {:get_next, self()})
    receive do
      {:next_page, page} -> page
    end
  end

  def loop(filename) do
    :xmerl_sax_parser.file(filename,
      event_fun: &event_fun/3,
      event_state: :top)
    loop_done
  end

  defp loop_done do
    receive do
      {:get_next, from} -> send(from, {:next_page, nil})
    end
    loop_done
  end

  defp event_fun({:startElement, _, 'page', _, _}, _, :top) do
    :page
  end

  defp event_fun({:startElement, _, 'text', _, _}, _, :page) do
    :text
  end

  defp event_fun({:characters, chars}, _, :text) do
    s = List.to_string(chars)
    receive do
      {:get_next, from} -> send(from, {:next_page, s})
    end
    :text
  end

  defp event_fun({:endElement, _, 'text', _}, _, :text) do
    :page
  end

  defp event_fun({:endElement, _, 'page', _}, _, :page) do
    :top
  end

  defp event_fun({:endDocument}, _, state) do
    receive do
      {:get_next, from} -> send(from, {:done})
    end
    state
  end

  defp event_fun(_, _, state) do
    state
  end
end
由于代码使用的是
SAX
解析器,我希望内存占用保持不变。当我尝试使用

Enum.each(1..2000, fn(x) -> Pages.next(Process.whereis(:pages)); end)
:pages
进程根据
:observer.start()
使用
1,1 GB
内存。当我试图阅读10000页时,整个过程崩溃了:

Crash dump is being written to: erl_crash.dump...done
eheap_alloc: Cannot allocate 5668310376 bytes of memory (of type "heap").
当我使用dump viewer打开erl_crash.dump时,我看到以下内容:

上面的代码有问题吗?GC不够快吗?虽然我可以看到每个进程的内存,但它并不能告诉我很多。我怎么才能知道这些记忆到底去了哪里

另外,这里有一个到今天的崩溃转储的链接:。
原子数为14490,
MsgQ
对于
:pages
为2,对于所有其他过程为0。

默认的最大原子数略高于。考虑到英文维基百科和维基百科,我认为这可能是罪魁祸首

此外,在Elixir上尝试下面的代码失败,只出现了一个“堆栈崩溃错误”


但是如果我使用环境变量
ELIXIR\u ERL\u OPTIONS=“+t 5000000”
将atom限制提高到大约500万,问题就会消失。

当它崩溃时,你会得到什么错误消息?我添加了错误消息可能它正在填充atom表?请参见xmerl上的。“我发现一个问题是xmerl为它从输入解析的每个元素名或名称空间URI生成新的原子。”。这里的答案建议使用erlsom sax解析器而不是xmerl。谢谢,我不认为这是atom表。原子是独立于过程的,对吗?但是dump告诉我们应该归咎于
:pages
进程,所以这是另外一回事。即使代码在另一个erlang进程中运行,atom表也会在运行的VM进程中全局运行。我将在下面的回答中详细说明。这似乎是xmerl中的一个重大疏忽。考虑到这是执行erlang服务的最简单方法,您可能会认为他们使用了二进制文件或字符串。
Enum.each(1..2000000, fn (x) ->
  x
  |> Integer.to_string
  |> String.to_atom
end)