我正在尝试减少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
和b
都少,但我想这不是没有运行时间上的显著惩罚。
似乎峰值内存分配与调用apply
中考虑的列数呈正相关关系,但为什么?调用apply
是否会导致内存分配超出迭代范围?我本希望gc
在每次迭代结束前释放任何内部临时对象(或将其标记为未使用)。
使用data.frame
上的lapply
以及替换quantile
的不同函数均可重现此行为。
我有一种感觉,我正在忽略R
中内存使用行为的一个非常基本的方面,但仍然无法理解。最终,我的问题是:如何在像上面示例中的情况下进一步减少内存占用?
提前感谢您的帮助,如有不准确之处请指出。
编辑:
根据@ChristopherLouden的建议,我使用了对gc
的调用来代替mem
,结果三种情况都被描述为使用了约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)
}