意外的R内存管理行为

3

最近几天我一直在寻找我编写的R程序中的内存泄漏问题。后来发现原来是由于我不太了解一些R语言特性所致,我的猜测是与promises和lazy evaluation有关。以下是一个重现该问题的示例:

M <- matrix(rnorm(1E7), 1000)
format(object.size(M), "Mb") ## An 80 Mbs matrix
gc() ## Memory usage should be around 80 Mbs
LF <- apply(M, 1, function(X) {sdX <- sd(X); function(X) X / sdX})
format(object.size(LF), "Mb") ## 2.9 Mb (isn't it a lot for a few functions? but it's not really the point)
gc() ## Memory usage is at 158 Mbs event though our workspace only contains two objects of 80 and 2.9 Mbs
rm(M)
gc() ## Back to around 80 Mbs but M is gone
rm(LF)
gc() ## Back to normal

如果我们重复操作的次数太多,您会发现内存使用量会失控。看起来 R 需要存储整个矩阵才能调用LF中的函数。当我们在LF中创建函数时会发生什么?有什么解决方法吗?


2
你正在创建闭包。请查看 ls(envir = environment(LF[[1]]))。R必须将这些对象与每个函数关联起来,否则如果您从全局环境中删除了M,它们将无法工作。我的建议是:不要这样做。如果您描述了为什么要这样做,我们可以提供替代方案。 - Roland
目标是创建能够转换一组变量的函数。在这个例子中,矩阵的每一列都是一个不同的变量。请注意,这只是我在程序中所做的简化版本。我知道 R 必须将 sdX 存储在某个地方,但为什么它要存储整个列呢?它只需要存储小的 sdX 值就可以了。 - eaglefreeman
1个回答

1
你返回的函数所在的封闭环境是传递给apply函数的本地环境。显然,函数参数必须存储在此环境中。通常,在调用后此环境会丢失,但是因为你返回了一个闭包,所以你可以保留它。你可以删除不需要的对象:
LF <- apply(M, 1, function(X) {sdX <- sd(X); rm("X"); function(X) X / sdX})
ls(envir = environment(LF[[1]]))
#[1] "sdX"

然而,我仍然不明白为什么要使用闭包,并建议重新设计整个方法。例如,在这个特定的例子中,我会返回标准差,并将它们作为参数传递给转换函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接