Elixir 使用xmerl读取大型XML文件会使节点崩溃
我有以下代码可以读取wikipedia转储文件(~50 GB)并根据请求交付页面: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,
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)