Frage Schwerwiegender Speicherverlust beim Iterativen Analysieren von XML-Dateien


Kontext

Beim Iterieren einer Reihe von Rdata-Dateien (die jeweils einen Zeichenvektor von HTML-Code enthalten), die geladen, analysiert (über XML Funktionalität) und dann wieder aus dem Speicher entfernt, erlebe ich ein von Bedeutung erhöhen in einem Speicherverbrauch des Prozesses (der Prozess wird letztendlich beendet).

Es scheint nur so

  • Befreien von Objekten über free(),
  • Entfernen sie über rm() und
  • Laufen gc() 

haben keine Effekte, so kumuliert der Speicherverbrauch, bis kein Speicher mehr übrig ist.

EDIT 2012-02-13 23:30:00

Dank der wertvollen Einblicke, die der Autor und der Betreuer des Pakets teilen XML, Duncan Temple Lang (wieder: Ich schätze es wirklich sehr!), Scheint das Problem eng mit der Art und Weise zusammenzuhängen, wie externe Zeiger freigegeben werden und wie die Garbage Collection im XML-Paket behandelt wird. Duncan hat eine Bugfix-Version des Pakets (3.92-0) herausgegeben, die bestimmte Aspekte des Parsens von XML und HTML konsolidiert und eine verbesserte Garbage-Collection bietet, bei der das Objekt, das den externen Pointer enthält, nicht mehr explizit freigegeben werden muss free(). Sie finden den Quellcode und eine Windows-Binärdatei bei Duncan Omega-Webseite.


BEARBEITEN 2012-02-13 23:34:00

Leider scheint die neue Paketversion die Probleme, denen ich begegne, in dem kleinen, kleinen Beispiel, das ich zusammengestellt habe, immer noch nicht zu beheben. Ich folgte einem Vorschlag und vereinfachte das Beispiel ein wenig, um es leichter zu verstehen und die relevanten Funktionen zu finden, bei denen etwas schief zu laufen scheint (Funktionen überprüfen) ./lib/exampleRun.R und .lib/scrape.R).


BEARBEITEN 2012-02-14 15:00:00

Duncan schlug vor, zu versuchen, das geparste Dokument explizit über zu befreien .Call("RS_XML_forceFreeDoc", html). Ich habe einen logischen Schalter in das Beispiel eingefügt (do.forcefree im Drehbuch ./scripts/memory.R) dass, wenn auf eingestellt TRUE, werde genau das tun. Leider hat dies meine R-Konsole zum Absturz gebracht. Es wäre großartig, wenn jemand dies auf seinem Rechner überprüfen könnte! Eigentlich ist der Doc sollte automatisch freigegeben werden, wenn Sie die neueste Version von XML verwenden (siehe oben). Die Tatsache, dass es nicht scheint, ist ein Fehler (nach Duncan).


BEARBEITEN 2012-02-14 23:12:00

Duncan hat noch eine weitere Version von XML (3.92-1) auf seiner Omega-Website veröffentlicht Omega-Webseite. Dies sollte das Problem im Allgemeinen beheben. Ich habe jedoch mit meinem Beispiel kein Glück, da ich immer noch denselben Speicherverlust erlebe.


EDIT 2012-02-17 20:39:00> LÖSUNG!

JA! Duncan hat den Fehler gefunden und repariert! Es war ein kleiner Tippfehler in einem Windows-Skript, das erklärte, warum der Fehler unter Linux, Mac OS usw. nicht angezeigt wurde. Schauen Sie sich die neueste Version an 3.92-2.! Der Speicherverbrauch ist jetzt so konstant wie beim iterativen Analysieren und Verarbeiten von XML-Dateien!

Nochmals vielen Dank an Duncan Temple Lang und an alle anderen, die auf diese Frage geantwortet haben!


>>> LEGACY TEILE DER ORIGINALFRAGE <<<

Beispiel Anweisungen (bearbeitet 2012-02-14 15:00:00)

  1. Download Ordner 'Erinnerung' Von meinem Github Repo.
  2. Öffne das Skript ./scripts/memory.R und setze a) deine Arbeitsverzeichnis beim Zeile 6, b) die Beispielbereich beim Zeile 16 c) ob die Freigabe des geparsten Dokuments erzwungen werden soll oder nicht Linie 22. Beachten Sie, dass Sie immer noch die alten Skripts finden können. sie werden von einem "getaggt"ERBE"am Ende des Dateinamens.
  3. Führen Sie das Skript aus.
  4. Untersuchen Sie die neueste Datei ./memory_<TIMESTAMP>.txt um den Anstieg der protokollierten Speicherzustände über die Zeit zu sehen. Ich habe zwei Textdateien eingeschlossen, die aus meinen eigenen Testläufen entstanden sind.

Dinge, die ich in Bezug auf Speicherkontrolle getan habe

  • Sicherstellen, dass ein geladenes Objekt erneut über gelöscht wird rm() am Ende jeder Iteration.
  • Beim Parsen von XML-Dateien habe ich Argumente festgelegt addFinalizer=TRUE, entfernte alle R-Objekte, die einen Verweis auf das geparste XML-Dokument haben, bevor der C-Zeiger über freigegeben wurde free() und Entfernen des Objekts, das den externen Zeiger enthält.
  • Hinzufügen eines gc() hier und da.
  • versuchen, den Rat in Duncan Temple Lang zu folgen Anmerkungen über die Speicherverwaltung bei Verwendung seines XML-Pakets (ich muss jedoch zugeben, dass ich nicht vollständig verstanden habe, was dort steht)

EDIT 2012-02-13 23:42:00: Wie ich oben ausgeführt habe, werden explizite Aufrufe an free() gefolgt von rm() sollte nicht mehr nötig sein, also habe ich diese Anrufe kommentiert.

Systeminformationen

  • Windows XP 32 Bit, 4 GB RAM
  • Windows 7 32 Bit, 2 GB RAM
  • Windows 7 64 Bit, 4 GB RAM
  • R 2.14.1
  • XML 3.9-4
  • XML 3.92-0 wie gefunden bei http://www.omegahat.org/RSXML/

Erste Ergebnisse vom 2012-02-09 01:00:00

  1. Das Ausführen des Webscraping-Szenarios auf mehreren Maschinen (siehe Abschnitt "Systeminfo" oben) führt immer zu einer Speicherauslastung meines R-Prozesses nach etwa 180 - 350 Iterationen (abhängig von OS und RAM).
  2. Das Ausführen des Plain-Rdata-Szenarios führt zu einem konstanten Speicherverbrauch dann und nur dann, wenn Sie setzen einen expliziten Aufruf über den Garbage Collector gc() in jeder Iteration; sonst erleben Sie das gleiche Verhalten wie im Webscraping-Szenario.

Fragen

  1. Irgendeine Idee, was die Speicherzunahme verursacht?
  2. Irgendwelche Ideen, wie man das umgeht?

Ergebnisse vom 2012-02-013 23:44:00

Ausführen des Beispiels in ./scripts/memory.R Auf mehreren Rechnern (siehe Abschnitt "System Info" oben) wird der Speicherverbrauch meines R-Prozesses nach ca. 180 - 350 Iterationen (abhängig von OS und RAM) immer noch aufgebraucht.

Es ist immer noch ein offensichtlicher Anstieg des Speicherverbrauchs zu beobachten, und obwohl es nicht so viel zu sein scheint, wenn ich nur auf die Zahlen schaue, starben meine R-Prozesse immer irgendwann an diesem Punkt.

Unten habe ich ein paar Zeitreihen gepostet, die aus der Ausführung meines Beispiels in einer WinXP 32 Bit Box mit 2 GB RAM resultieren:

TS_1 (XML 3.9-4, 2012-02-09)

29.07 33.32 30.55 35.32 30.76 30.94 31.13 31.33 35.44 32.34 33.21 32.18 35.46 35.73 35.76 35.68 35.84 35.6 33.49 33.58 33.71 33.82 33.91 34.04 34.15 34.23 37.85 34.68 34.88 35.05 35.2 35.4 35.52 35.66 35.81 35.91 38.08 36.2

TS_2 (XML 3.9-4, 2012-02-09)

28.54 30.13 32.95 30.33 30.43 30.54 35.81 30.99 32.78 31.37 31.56 35.22 31.99 32.22 32.55 32.66 32.84 35.32 33.59 33.32 33.47 33.58 33.69 33.76 33.87 35.5 35.52 34.24 37.67 34.75 34.92 35.1 37.97 35.43 35.57 35.7 38.12 35.98

Fehlermeldung, die TS_2 zugeordnet ist

[...]
Scraping html page 30 of ~/data/rdata/132.rdata
Scraping html page 31 of ~/data/rdata/132.rdata
error : Memory allocation failed : growing buffer
error : Memory allocation failed : growing buffer
I/O error : write error
Scraping html page 32 of ~/data/rdata/132.rdata
Fehler in htmlTreeParse(file = obj[x.html], useInternalNodes = TRUE, addFinalizer =     TRUE): 
 error in creating parser for (null)
> Synch18832464393836

TS_3 (XML 3.92-0, 2012-02-13)

20.1 24.14 24.47 22.03 25.21 25.54 23.15 Uhr 23.5 26.71 24.6 27.39 24.93 28.06 25.64 28.74 26.36 29.3 27.07 30.01 27.77 28.13 31.13 28.84 31.79 29.54 32.4 30.25 33.07 30.96 33.76 31.66 34.4 32.37 35.1 33.07 35.77 38.23 34.16 34.51 34.87 35.22 35.58 35.93 40.54 40.9 41.33 41.6

Fehlermeldung, die TS_3 zugeordnet ist

[...]
---------- status: 31.33 % ----------

Scraping html page 1 of 50
Scraping html page 2 of 50
[...]
Scraping html page 36 of 50
Scraping html page 37 of 50
Fehler: 1: Memory allocation failed : growing buffer
2: Memory allocation failed : growing buffer

Bearbeiten 2012-02-17: Bitte helfen Sie mir, Zählerwert zu überprüfen

Sie würden mir einen großen Gefallen tun, wenn Sie den folgenden Code ausführen könnten. Es dauert nicht mehr als 2 Minuten Ihrer Zeit. Alles, was Sie tun müssen, ist

  1. Laden Sie ein Rdatendatei und speichern Sie es als seed.Rdata.
  2. Laden Sie das Skript herunter, das meinen enthält Kratzfunktion und speichern Sie es als scrape.R.
  3. Geben Sie den folgenden Code ein, nachdem Sie das Arbeitsverzeichnis entsprechend festgelegt haben.

Code:

setwd("set/path/to/your/wd")
install.packages("XML", repos="http://www.omegahat.org/R")
library(XML)
source("scrape.R")
load("seed.rdata")
html <- htmlParse(obj[1], asText = TRUE)
counter.1 <- .Call("R_getXMLRefCount", html)
print(counter.1)
z <- scrape(html)
gc()
gc()
counter.2 <- .Call("R_getXMLRefCount", html)
print(counter.2)
rm(html)
gc()
gc()

Ich bin besonders interessiert an den Werten von counter.1 und counter.2 welche sollte Sein 1 in beiden Anrufen. Auf allen Maschinen hat Duncan das getestet. Wie sich jedoch herausstellt counter.2 hat einen Wert 259 auf allen meinen Maschinen (siehe Details oben) und genau das verursacht mein Problem.


14
2018-02-10 05:48


Ursprung


Antworten:


Von dem XML auf der Website des Pakets scheint der Autor Duncan Temple Lang bestimmte Fragen zur Speicherverwaltung ausführlich beschrieben zu haben. Siehe diese Seite: "Speicherverwaltung im XML-Paket".

Ehrlich gesagt, ich bin nicht im Detail in den Details, was hier mit Ihrem Code und dem Paket vor sich geht, aber ich denke, Sie werden entweder die Antwort auf dieser Seite finden, speziell in dem Abschnitt namens "Probleme"oder in direkter Verbindung mit Duncan Temple Lang.


Update 1. Eine Idee, die Macht Arbeit ist es, die multicore und foreach Pakete (d.h. listResults = foreach(ix = 1:N) %dopar% {your processing;return(listElement)}. Ich denke, dass für Windows Sie brauchen doSMP, oder vielleicht doRedis; Unter Linux benutze ich doMC. In jedem Fall erhalten Sie durch die Parallelisierung des Ladevorgangs einen höheren Durchsatz. Der Grund, aus dem ich denke, dass Sie von der Speichernutzung etwas profitieren können, ist, dass es sein könnte, dass das Forking von R zu einer unterschiedlichen Speicherbereinigung führen könnte, da jeder erzeugte Prozess beendet wird, wenn er abgeschlossen ist. Dies funktioniert nicht garantiert, aber es kann sowohl Speicher- als auch Geschwindigkeitsprobleme beheben.

Beachten Sie jedoch: doSMP hat seine eigenen Idiosynkrasien (d. h. Sie haben möglicherweise noch einige Speicherprobleme). Es gab andere Q & As zu SO, die einige Probleme erwähnten, aber ich würde es trotzdem versuchen.


7



@Rappster Mein R stürzt nicht ab, wenn ich das erste Mal überprüfe und stelle sicher, dass das XML-Dokument existiert und rufe dann die C-Funktion auf, um den Speicher zu realisieren.

 for (i in 1:1000) {

  pXML<-xmlParse(file)

if(exists("pXML")){
  .Call("RS_XML_forceFreeDoc", pXML)
                  }
}

-2