背景
在迭代加载、分析(通过XML功能)和从内存中删除的一组Rdata文件(每个文件包含HTML代码的字符向量)时,我发现一个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)
强制显式释放已解析的文档。我在示例中包含了一个逻辑开关(位于脚本./scripts/memory.R
中的do.forcefree
),如果设置为TRUE
,则会执行此操作。不幸的是,这使我的R控制台崩溃了。真的很棒,如果有人能在他们的计算机上验证这一点!实际上,当使用XML的最新版本时,应自动释放文档(请参见以上内容)。它没有这样做似乎是一个错误(根据Duncan)。
编辑 2012-02-14 23:12:00
Duncan在他的Omegahat网站(Omegahat网站)上推出了另一个XML版本(3.92-1),这应该可以通常解决问题。然而,我对我的示例不太幸运,因为我仍然遇到相同的内存泄漏问题。
编辑 2012-02-17 20:39:00 > 解决方案!
是的!Duncan找到并修复了错误!这是一个仅限Windows的脚本中的小错别字,这就解释了为什么在Linux、Mac OS等系统中没有显示此错误。查看最新版本3.92-2。!当迭代解析和处理XML文件时,内存消耗现在非常稳定!
再次特别感谢Duncan Temple Lang以及每个回答这个问题的人!
>>> 原始问题的旧部分<<<
示例说明(已编辑2012-02-14 15:00:00)
- 从我的Github repo下载'memory'文件夹。
- 打开脚本
./scripts/memory.R
,并设置a)第6行的工作目录,b)第16行的示例范围以及c)是否在第22行强制释放已解析的文档。请注意,您仍然可以找到旧脚本;它们由文件名末尾的"LEGACY"标记。 - 运行脚本。
- 调查最新的文件
./memory_<TIMESTAMP>.txt
,以查看随时间记录的内存状态增加情况。我包括了两个文本文件,这是我自己的测试运行结果。
我对内存控制所做的事情
- 确保在每个迭代的末尾通过
rm()
删除已加载的对象。 - 解析XML文件时,我设置了参数
addFinalizer=TRUE
,在释放C指针之前删除所有引用已解析XML文档的R对象,并删除包含外部指针的对象。 - 这里添加一个
gc()
。 - 尝试遵循Duncan Temple Lang在使用其XML软件包时有关内存管理的笔记中的建议(尽管我必须承认我没有完全理解那里所说的)
编辑 2012-02-13 23:42:00:
如我上面所指出的,不再需要显式调用free()
,然后是rm()
,因此我注释了这些调用。
系统信息
- Windows XP 32位,4 GB RAM
- Windows 7 32位,2 GB RAM
- Windows 7 64位,4 GB RAM
- R 2.14.1
- XML 3.9-4
- XML 3.92-0,位于http://www.omegahat.org/RSXML/
2012-02-09 01:00:00的初步发现
- 在几台机器上运行Web爬取方案(请参见上面的“系统信息”部分)后,总是在大约180-350次迭代后破坏了我的R进程的内存消耗。
- 如果您在每个迭代中通过
gc()
显式调用垃圾收集器,则运行纯rdata方案会产生恒定的内存消耗仅当且仅当;否则,您将遇到与Web爬取方案相同的行为。
问题
- 有任何想法是什么导致了内存增加?
- 有任何想法如何解决这个问题吗?
2012-02-013 23:44:00的发现
在几台机器上运行./scripts/memory.R
示例仍然会在大约180-350次迭代后破坏我的R进程的内存消耗(具体取决于OS和RAM)。
尽管只看数字时可能不那么明显,但仍然存在内存消耗的明显增加,而且尽管只看数字时可能不那么明显,但我的R进程总是在某个时候死亡。
以下是在WinXP 32位系统,2GB RAM上运行示例后产生的几个时间序列: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年2月17日:请帮我验证计数器的值
如果您能运行以下代码,那将对我大有帮助。 不需要超过2分钟时间。您需要做的是:
代码:
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测试的所有机器上,它们的值都是1
。然而,事实证明,在我所有的机器上,counter.2
的值为259
(请参见上面的详细信息),这正是导致我的问题的原因。
Rprofmem
和Rprof
?我也会存储要加载的每个文件的大小。顺便说一句,我从未遇到过这个问题,并且我确实迭代了大量的数据和文件。我倾向于在Linux中完成较重的工作,但是我也不记得在Windows中遇到过这个问题。有许多可能的原因,而且似乎其他人尚未重现这个问题。 - IteratorRprofmem
和Rprof
。看起来更像是XML而不是Rdata导致了问题,但我需要再次确认。 - Rappster