Серьезный утечка памяти при итеративном анализе XML файлов

Контекст

При повторном запуске по набору файлов Rdata (каждый из которых содержит вектор символов HTML-кода), которые анализируются (через XML), а затем снова удалили из памяти, я ощущаю увеличение значительного R "(в конечном итоге уничтожает процесс).

Кажется, что

  • освобождение объектов через free(),
  • удаляя их через rm() и
  • running gc()

не имеют никаких эффектов, поэтому потребление памяти накапливается до тех пор, пока не останется больше памяти.

EDIT 2012-02-13 23:30:00

Благодаря ценной информации, предоставленной автором и сторонником пакета XML, Duncan Temple Lang (снова: я очень ценю это!), проблема, похоже, тесно связана с тем, как внешние указатели освобождаются и как сбор мусора обрабатывается в пакете XML. Duncan выпустил исправленную версию пакета (3.92-0), в которой были объединены определенные аспекты анализа XML и HTML, а также улучшена сборка мусора, где уже не требуется явно освобождать объект, содержащий внешний указатель, через free(). Вы найдете исходный код и двоичный файл Windows в Duncan веб-сайт Omegahat.


EDIT 2012-02-13 23:34:00

К сожалению, новая версия пакета по-прежнему не исправляет проблемы, с которыми я сталкиваюсь в маленьком примере, который я собрал. Я последовал некоторому предложению и немного упростил этот пример, упростив понимание и найти соответствующие функции, в которых, кажется, что-то не так (проверьте функции ./lib/exampleRun.R и .lib/scrape.R).


EDIT 2012-02-14 15:00:00

Дункан предложил попытаться принудительно освободить проанализированный документ через .Call("RS_XML_forceFreeDoc", html). Я включил логический переключатель в примере (do.forcefree в script ./scripts/memory.R), который, если установлен в TRUE, сделает именно это. К сожалению, это привело к краху консоли R. Было бы здорово, если бы кто-то мог проверить это на своей машине! Фактически, документ должен автоматически освобождаться при использовании последней версии XML (см. Выше). Тот факт, что это не кажется ошибкой (по словам Дункана).


EDIT 2012-02-14 23:12:00

Дункан нажал еще одну версию XML (3.92-1) на свой веб-сайт Omegahat веб-сайт Omegahat. Это должно решить проблему в целом. Тем не менее, мне кажется, что мне не повезло с моим примером, поскольку я все еще испытываю те же утечки памяти.


EDIT 2012-02-17 20:39:00 > РЕШЕНИЕ!

ДА! Дункан нашел и исправил ошибку! Это была небольшая опечатка в Windows-only script, которая объясняла, почему ошибка не отображалась в Linux, Mac OS и т.д. Проверьте последнюю версию 3.92 -2.! Потребление памяти теперь столь же постоянное, как и при итеративном синтаксическом анализе и обработке XML файлов!

Особая благодарность Дункану Храм Лангу и спасибо всем, кто ответил на этот вопрос!


→ > ЗАКОНОМЕРНЫЕ ЧАСТИ ОРИГИНАЛЬНОГО ВОПРОСА < <

Примеры инструкций (отредактировано 2012-02-14 15:00:00)

  • Загрузите папку 'memory' из моего Github repo.
  • Откройте script ./scripts/memory.R и установите a) ваш рабочий каталог на строке 6, b) область примера в строке 16, а также c) для принудительного освобождения анализируемого документа или нет в строке 22. Обратите внимание, что вы все равно можете найти старые сценарии; они "помечены" символом " LEGACY" в конце имени файла.
  • Запустите script.
  • Изучите последний файл ./memory_<TIMESTAMP>.txt, чтобы увидеть увеличение количества зарегистрированных состояний памяти во времени. Я включил два текстовых файла, которые были результатом моих собственных тестовых прогонов.

Что я делал в отношении управления памятью

  • убедитесь, что загруженный объект снова удален с помощью rm() в конце каждой итерации.
  • При анализе XML файлов я установил аргумент addFinalizer=TRUE, удалил все объекты R, которые имеют ссылку на анализируемый XML-документ, прежде чем освободить C-указатель через free() и удалить объект, содержащий внешний указатель.
  • добавление gc() здесь и там.
  • пытается следовать совету в Duncan Temple Lang заметкипо управлению памятью при использовании своего пакета XML (я должен признать, что я не полностью понял, что там указано)

EDIT 2012-02-13 23:42:00: Как я уже указывал выше, явные вызовы free(), а затем rm() больше не нужны, поэтому я прокомментировал эти вызовы.

Информация о системе

  • Windows XP 32 бит, 4 ГБ оперативной памяти
  • Windows 7 32 бит, 2 ГБ оперативной памяти
  • Windows 7 64 бит, 4 ГБ оперативной памяти
  • R 2.14.1
  • XML 3.9-4
  • XML 3.92-0, найденный в http://www.omegahat.org/RSXML/

Первоначальные результаты с 2012-02-09 01:00:00

  • Запуск сценария веб-каскадов на нескольких машинах (см. раздел "Сведения о системе" выше) всегда разрушает потребление памяти моего процесса R после примерно 180 - 350 итераций (в зависимости от ОС и ОЗУ).
  • Запуск сценария простой rdata дает постоянное потребление памяти тогда и только тогда, когда вы устанавливаете явный вызов сборщика мусора через gc() на каждой итерации; иначе вы испытываете то же поведение, что и в сценарии webscraping.

Вопросы

  • Любая идея, что вызывает увеличение памяти?
  • Любые идеи, как обойти это?

Выводы по состоянию на 2012-02-013 23:44:00

Запуск примера в ./scripts/memory.R на нескольких машинах (см. раздел "Сведения о системе" выше) по-прежнему разрушает потребление памяти моего процесса R примерно после 180 - 350 итераций (в зависимости от ОС и ОЗУ).

По-прежнему наблюдается очевидное увеличение потребления памяти, и хотя это может показаться не таким уж большим, просто глядя на цифры, мои R-процессы всегда умирают в какой-то момент из-за этого.

Ниже я опубликовал пару временных рядов, которые появились в результате запуска моего примера в битве WinXP 32 бит с 2 ГБ оперативной памяти:

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

Сообщение об ошибке, связанное с TS_2

[...]
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 +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

Сообщение об ошибке, связанное с TS_3

[...]
---------- 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

Редактировать 2012-02-17: пожалуйста, помогите мне проверить значение счетчика

Вы сделали бы мне огромную услугу, если бы вы могли запустить следующий код. Это займет не более 2 минут вашего времени. Все, что вам нужно сделать, это

  • Загрузите файл Rdata и сохраните его как seed.Rdata.
  • Загрузите script, содержащий мою функцию соскабливания и сохраните ее как scrape.R.
  • Введите следующий код после установки рабочего каталога соответствующим образом.

код:

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()

Меня особенно интересуют значения counter.1 и counter.2, которые должны быть 1 в обоих вызовах. Фактически, это на всех машинах, которые Duncan проверил на этом. Однако, как оказалось, counter.2 имеет значение 259 на всех моих машинах (см. Подробности выше) и точно, что вызывает мою проблему.

Ответы

Ответ 1

На веб-странице пакета XML кажется, что автор Duncan Temple Lang довольно подробно описал некоторые проблемы управления памятью. См. Эту страницу: Управление памятью в пакете XML.

Честно говоря, я не разбираюсь в деталях того, что происходит здесь с вашим кодом и пакетом, но я думаю, что вы найдете либо ответ на этой странице, особенно в разделе "Проблемы" или в прямом сообщении с Duncan Temple Lang.


Обновление 1. Идея, которая может работать, заключается в использовании пакетов multicore и foreach (т.е. listResults = foreach(ix = 1:N) %dopar% {your processing;return(listElement)}. Я думаю, что для Windows вам понадобится doSMP или, возможно, doRedis; под Linux, Я использую doMC. В любом случае, распараллеливая загрузку, вы получите более высокую пропускную способность. Причина, по которой я думаю, что вы можете извлечь выгоду из использования памяти, заключается в том, что это может быть то, что forking R может привести к различной очистке памяти, так как каждый порожденный процесс убивается, когда он завершен. Это не гарантирует работу, но может решить проблемы с памятью и скоростью.

Обратите внимание, что: doSMP имеет свои собственные особенности (т.е. у вас могут быть проблемы с памятью). Там были другие вопросы и ответы. Как и в случае с SO, которые упомянули некоторые проблемы, но я все равно даю ему шанс.

Ответ 2

@Rappster My R не сбой при первом проверке и убедитесь, что XML-документ существует, а затем вызывает функцию C для реализации памяти.

 for (i in 1:1000) {

  pXML<-xmlParse(file)

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