Серьезный утечка памяти при итеративном анализе 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)
}
}