我正在尝试减少R包的内存占用,并注意到我似乎无法抑制的行为。请参阅以下示例:
x <- matrix(runif(1.5e7), ncol = 200)
## CASE 1: Test with half of columns
gc(reset = TRUE)
a <- apply(x[, 1:100], 2, quantile)
gc()
# used (Mb) gc trigger (Mb) max used (Mb)
# Ncells 190549 10.2 407500 21.8 222055 11.9
# Vcells 15292303 116.7 35490421 270.8 35484249 270.8
object.size(a)
# 4696 bytes
rm(a)
## CASE 2: Test with all columns
gc(reset = TRUE)
b <- apply(x, 2, quantile)
gc()
# used (Mb) gc trigger (Mb) max used (Mb)
# Ncells 190824 10.2 407500 21.8 245786 13.2
# Vcells 15293740 116.7 39292189 299.8 39286529 299.8
object.size(b)
# 8696 bytes
rm(b)
## CASE 3: Test with all columns + call gc
gc(reset = TRUE)
c <- apply(x, 2, function(i) { r <- quantile(i); gc(); r })
gc()
# used (Mb) gc trigger (Mb) max used (Mb)
# Ncells 191396 10.3 407500 21.8 197511 10.6
# Vcells 15294307 116.7 45737818 349.0 30877185 235.6
object.size(c)
# 8696 bytes
rm(c)
a
和b
相差仅约4kb但垃圾收集器报告案例1和2的峰值内存使用量之间的差异为~30mb。c
使用的内存少于两者a
和c
,我想在运行时不会受到相当大的惩罚。
峰值内存分配似乎与调用apply
时考虑的列数正相关,但为什么呢?调用apply
会导致内存分配超出迭代范围吗?我希望在每次迭代结束之前gc
释放(或标记为未使用)任何内部临时值。
可以使用lapply
替换data.frame
以及使用不同的函数代替quantile
来重现此行为。
我的印象是我忽略了R
中内存使用行为的一个非常基本的方面,但仍然无法绕过它。最后,我的问题是:如上例所示,如何进一步减少内存占用?
提前致谢,不要犹豫,在我的问题中指出任何不准确之处。
编辑:
根据@ ChristopherLouden的建议,我使用mem
来代替gc
,并且所有三个案例被描述为占用~126.9182mb。
## http://adv-r.had.co.nz/memory.html#garbarge-collection
mem <- function() {
bit <- 8L * .Machine$sizeof.pointer
if (!(bit == 32L || bit == 64L)) {
stop("Unknown architecture", call. = FALSE)
}
node_size <- if (bit == 32L) 28L else 56L
usage <- gc()
sum(usage[, 1] * c(node_size, 8)) / (1024 ^ 2)
}
答案 0 :(得分:4)
我认为Hadley Wickham的Memory Chapter of Advanced R Programming中的这句话最能总结出这种差异的原因。
垃圾收集通常会懒散地发生:当需要更多空间时,R会调用gc()。实际上,在函数终止后,R可能会保留在内存中,但它会在需要时立即释放它
本章还有一个名为mem()
的好函数,可以让你更清楚地看到代码块使用的内存比gc()
允许的多少。如果时间允许,我会用Wickham的mem()
函数重新进行测试。
修改强>
正如彼得指出的那样,mem()
函数已被弃用。请改用 pryr 包中的mem_used()
功能。