迭代解析XML文件时严重的内存泄漏

Rap*_*ter 14 xml memory-leaks r bigdata web-scraping

上下文

当迭代一组Rdata文件(每个包含HTML代码的字符向量),这些文件被加载,分析(通过XML功能),然后再次从内存中删除,我体验到R进程的内存消耗显着增加(杀死了过程最终).

它似乎就像

  • 释放物体free(),
  • 通过rm()和删除它们
  • 赛跑 gc()

没有任何影响,所以内存消耗累积,直到没有更多的内存.

编辑2012-02-13 23:30:00

感谢包XML的作者和维护者共享的宝贵见解,Duncan Temple Lang(再次:我非常感谢!),问题似乎与释放外部指针的方式以及如何处理垃圾收集密切相关XML包.Duncan发布了一个错误修复版本的软件包(3.92-0),它整合了解析XML和HTML的某些方面,并具有改进的垃圾收集功能,不再需要显式释放包含外部指针的对象free().您可以在Duncan的Omegahat网站上找到源代码和Windows二进制文件.


编辑2012-02-13 23:34:00

不幸的是,新的软件包版本似乎仍然没有解决我在我放在一起的小小例子中遇到的问题.我遵循了一些建议并稍微简化了示例,使得更容易掌握并找到事情似乎出错的相关功能(检查功能./lib/exampleRun.R.lib/scrape.R).


编辑2012-02-14 15:00:00

Duncan建议尝试强制通过显式释放已解析的文档.Call("RS_XML_forceFreeDoc", html).我在示例中(do.forcefree在脚本中./scripts/memory.R)包含了一个逻辑开关,如果设置为TRUE,则会执行此操作.不幸的是,这让我的R控制台崩溃了.如果有人可以在他们的机器上验证这一点,那就太棒了!实际上,在使用最新版本的XML时,应该自动释放doc (参见上文).事实上它似乎不是一个错误(根据Duncan).


编辑2012-02-14 23:12:00

Duncan将另一个版本的XML(3.92-1)推送到他的Omegahat网站Omegahat网站.这应该解决一般问题.但是,我似乎对我的例子运气不好,因为我仍然遇到相同的内存泄漏.


编辑2012-02-17 20:39:00>解决方案!

是!邓肯发现并修复了这个错误!在一个仅限Windows的脚本中,这是一个小错字,它解释了为什么这个bug没有在Linux,Mac OS等中显示.请查看最新版本3.92-2.!现在,内存消耗与迭代解析和处理XML文件时一样不变!

特别感谢Duncan Temple Lang,感谢响应这个问题的所有人!


>>>原始问题的遗留部分<<<

示例说明(编辑2012-02-14 15:00:00)

  1. 从我的Github仓库下载文件夹'memory'.
  2. 打通脚本./scripts/memory.R和设置)的工作目录第6行,b)将实施例范围,在第16行,以及c)中是否强制解析文档或不的释放在管线22.请注意,您仍然可以找到旧脚本; 它们由文件名末尾的" LEGACY " "标记" .
  3. 运行脚本.
  4. 调查最新文件./memory_<TIMESTAMP>.txt以查看记录的内存状态随时间的增加.我已经包含了两个由我自己的测试运行产生的文本文件.

我在内存控制方面做的事情

  • 确保rm()在每次迭代结束时再次删除已加载的对象.
  • 在解析XML文件时,我设置了参数addFinalizer=TRUE,在释放C指针之前删除了所有引用了解析的XML文档的R对象,free()并删除了包含外部指针的对象.
  • gc()这里和那里添加一个.
  • 试图在使用其XML包时遵循Duncan Temple Lang 关于内存管理的注意事项的建议(我不得不承认我并没有完全理解那里所说的内容)

编辑2012-02-13 23:42:00: 正如我上面指出的那样,不再需要显式调用free()后跟rm(),所以我评论了这些调用.

系统信息

初步调查结果截至2012-02-09 01:00:00

  1. 在几台机器上运行webscraping场景(参见上面的"系统信息"部分)总是在大约180到350次迭代(取决于操作系统和RAM)后破坏了我的R进程的内存消耗.
  2. 当且仅当gc()在每次迭代中设置对垃圾收集器的显式调用时,运行普通的rdata方案会产生恒定的内存消耗; 否则你会遇到与webscraping场景相同的行为.

问题

  1. 知道什么导致内存增加?
  2. 任何想法如何解决这个问题?

结果截至2012-02-013 23:44:00

./scripts/memory.R在几台机器上运行示例(参见上面的"系统信息"部分)在大约180到350次迭代(取决于操作系统和RAM)之后,仍会破坏我的R进程的内存消耗.

内存消耗量仍然明显增加,即使看到数字时看起来可能不那么多,但由于这个原因,我的R进程总会在某个时刻死亡.

下面,我发布了几个时间序列,这些时间序列来自在具有2 GB RAM的WinXP 32位盒上运行我的示例:

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

编辑2012-02-17:请帮我验证计数器值

如果您可以运行以下代码,那么我会帮到我. 你的时间不会超过2分钟.你需要做的就是

  1. 下载Rdata文件并将其另存为seed.Rdata.
  2. 下载包含我的抓取功能的脚本并将其保存为scrape.R.
  3. 相应地设置工作目录后,请输入以下代码.

码:

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()
Run Code Online (Sandbox Code Playgroud)

我在的值特别感兴趣,counter.1并且counter.2应该1在这两个电话.实际上,Duncan已经在所有机器上进行了测试.但是,事实证明我的所有机器counter.2都有价值259(详见上文),而这正是导致我出现问题的原因.

Ite*_*tor 7

XML软件包的网页上看,作者Duncan Temple Lang似乎已经广泛地描述了某些内存管理问题.请参阅此页:"XML包中的内存管理".

老实说,我不熟悉你的代码和包中发生的事情的细节,但我认为你要么在那个页面找到答案,特别是在"问题"一节中,或者直接与邓肯寺郎.


更新1. 可能有用的想法是使用multicoreforeach包(即listResults = foreach(ix = 1:N) %dopar% {your processing;return(listElement)}我认为对于Windows你需要doSMP,或者可能doRedis;在Linux下,我使用doMC.无论如何,通过并行加载,你会更快我认为你可以从内存使用中获得一些好处的原因是它可能是分叉R,可能导致不同的内存清理,因为每个生成的进程在完成时都会被杀死.这不能保证工作,但它可以解决内存和速度问题.

但请注意:doSMP它有自己的特性(即你可能仍然有一些内存问题).关于SO的其他问答提到了一些问题,但我还是试一试.