4

我有一个如下所示的双循环 ,问题是 R (2.15.2) 正在使用越来越多的内存,我不明白为什么。

虽然我知道这必须在内部循环中发生,因为rbind()我在那里做,但我不明白为什么当外部循环的新循环开始并且实际上对象( 'xmlCatcher' )被重用时,R 一直在抢内存:

# !!!BEWARE this example creates a lot of files (n=1000)!!!!

require(XML)

chunk <- function(x, chunksize){
        # source: http://stackoverflow.com/a/3321659/1144966
        x2 <- seq_along(x)
        split(x, ceiling(x2/chunksize))
    }

chunky <- chunk(paste("test",1:1000,".xml",sep=""),100)

for(i in 1:1000){
writeLines(c(paste('<?xml version="1.0"?>\n <note>\n    <to>Tove</to>\n    <nr>',i,'</nr>\n    <from>Jani</from>\n    <heading>Reminder</heading>\n    ',sep=""), paste(rep('<body>Do not forget me this weekend!</body>\n',sample(1:10, 1)),sep="" ) , ' </note>')
,paste("test",i,".xml",sep=""))
}

for(k in 1:length(chunky)){
gc()
print(chunky[[k]])
xmlCatcher <- NULL

for(i in 1:length(chunky[[k]])){
    filename    <- chunky[[k]][i]
    xml         <- xmlTreeParse(filename)
    xml         <- xmlRoot(xml)
    result      <- sapply(getNodeSet(xml,"//body"), xmlValue)
    id          <- sapply(getNodeSet(xml,"//nr"), xmlValue)
    dummy       <- cbind(id,result)
    xmlCatcher  <- rbind(xmlCatcher,dummy)
    }
save(xmlCatcher,file=paste("xmlCatcher",k,".RData"))
}

有人知道为什么会发生这种行为吗?请注意,所有对象(如“xmlCatcher”)在每个周期都被重用,因此我假设使用的 RAM 在第一个“块”周期后应该保持不变。

  • 垃圾收集不会改变任何事情。
  • 不使用 rbind 不会改变任何事情。
  • 使用更少的 xml 函数实际上会减少内存占用 - 但是为什么呢?

这是一个错误还是我错过了什么?

4

3 回答 3

7

你对重用内存的理解是wong。

当您创建新的 DummyCatcher 时,旧的 DummyCatcher 不再被引用,然后成为垃圾收集的候选者,这将在某个时候发生。

您不是在重用内存,而是在创建一个新对象并放弃旧对象。

垃圾收集将释放内存。

另外,我建议您查看 Rprofmem 来分析您的内存使用情况。

于 2012-12-21T12:00:13.890 回答
4

在本篇的第2章中,rbind作为贪吃者的一般手段进行了讨论。

你可以避免使用rbindinside 循环,

my.list <- vector('list', chunk[k])
for(i in 1:chunk[k]) {
   dummy <- dummy + 1
   my.list[[i]] <- data.frame(dummy)
}
DummyCatcher  <- do.call('rbind', my.list)
于 2012-12-21T10:28:36.713 回答
2

它的 XML 包很愚蠢!

The answer to this question came by Milan Bouchet-Valat here who proposed I should try to use the useInternalNodes=TRUE-option for xmlTreeParse. That stopped the RAM grabbing although there is also the possibility to manually handle memory-freeing. For further reading see: here.

于 2012-12-21T19:30:27.727 回答