Ich habe den folgenden Code, der eine wikipedia-Dump-Datei (~ 50 GB) und liefert Seiten auf Anfrage lautet:große XML-Datei mit xmerl Lesen stürzt der Knoten
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
Da der Code verwendet SAX
Parser würde ich erwarten, konstanter Speicherbedarf mit
Enum.each(1..2000, fn(x) -> Pages.next(Process.whereis(:pages)); end)
der :pages
Prozess verwendet 1,1 GB
Speicher nach :observer.start()
Wenn ich versuche ersten 2000 Seiten zu lesen. Wenn ich versuche, 10000 Seiten zu lesen, die ganze Sache Abstürze:
Crash dump is being written to: erl_crash.dump...done
eheap_alloc: Cannot allocate 5668310376 bytes of memory (of type "heap").
Wenn ich erl_crash.dump
mit Dump-Viewer zu öffnen Ich sehe folgendes:
Stimmt etwas nicht mit dem Code oben? Ist GC nicht schnell genug? Obwohl ich die Erinnerung pro Prozess sehen kann, sagt sie mir nicht viel. Wie kann ich sehen, wohin diese Erinnerung tatsächlich geht?
P.S. Hier ist ein Link zu einem Absturzspeicher von heute: https://ufile.io/becba. Die Anzahl der Atome ist 14490, die MsgQ
ist 2 für :pages
und 0 für alle anderen Prozesse.
Welche Fehlermeldung erhalten Sie, wenn es abstürzt? – legoscia
Ich habe die Fehlermeldung hinzugefügt – damluar
Vielleicht füllt es die Atom-Tabelle? Siehe [this thread] (http://erlang.org/pipermail/erlang-questions/2007-March/025592.html) auf xmerl. "Was ich finde, ist ein Problem, dass xmerl ** neue Atome ** für jeden Elementnamen oder ** Namespace-URI ** erzeugt, die es von der Eingabe analysiert." Die Antwort dort schlägt vor, den Erlsom Sax Parser anstelle von Xmerl zu verwenden. –