使用xmerl读取大型XML文件崩溃节点
我有下面的代码读取*转储文件(〜50 GB),并根据要求提供了网页:使用xmerl读取大型XML文件崩溃节点
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
阅读第2000页。当我尝试阅读10000页,整个事情崩溃:
Crash dump is being written to: erl_crash.dump...done
eheap_alloc: Cannot allocate 5668310376 bytes of memory (of type "heap").
当我使用dump观众我看到下面打开erl_crash.dump
:
出毛病了上面的代码? GC不够快吗?虽然我可以看到每个进程的内存,但它并没有告诉我很多。我怎样才能看到这个记忆究竟在哪里?
P.S.这里是从今天起的一个崩溃转储的链接:https://ufile.io/becba。 原子的数量是14490,MsgQ
对于:pages
是2,对于所有其他过程是0。
原子的默认最大数量略高于1 million atoms。鉴于英文*has over 5 million articles和xmerl seems to create an atom for each namespace URI,我认为它可能是罪魁祸首。
另外,在Elixir上尝试下面的代码会失败,只会出现“堆栈粉碎错误”。
Enum.each(1..2000000, fn (x) ->
x
|> Integer.to_string
|> String.to_atom
end)
但如果我提出了原子的限制像500万与环境变量ELIXIR_ERL_OPTIONS="+t 5000000"
,问题消失。
这看起来像是在xmerl中的一个大规模的监督。考虑到它像DOS最简单的方式来执行erlang服务,你会认为它们使用了二进制文件或字符串。 – rozap
当它崩溃时会得到什么错误信息? – legoscia
我添加了错误信息 – damluar
也许它正在填充原子表?请参阅xmerl上的[this thread](http://erlang.org/pipermail/erlang-questions/2007-March/025592.html)。 “我发现的一个问题是,xmerl **会为每个元素名称或**名称空间URI **产生新的原子**,它将从输入中解析出来。” 那里的答案建议使用erlsom sax解析器而不是xmerl。 –