我最近一直试图通过阅读和试验R中的内存使用来提高我的R编程技能。我最近试图在Hadley的“Advanced R”中重新创建一个例子,但得到了不同的结果。在this page的底部,Hadley设置了以下示例:
x <- data.frame(matrix(runif(100 * 1e4), ncol = 100))
medians <- vapply(x, median, numeric(1))
然后通过显示
来演示原始和非原始之间的区别for(i in 1:5) {
x[, i] <- x[, i] - medians[i]
print(c(address(x), refs(x)))
}
每次循环运行时都会复制(因为x是数据帧)。而
y <- as.list(x)
for(i in 1:5) {
y[[i]] <- y[[i]] - medians[i]
print(c(address(y), refs(y)))
}
修改y到位(因为y已被转换为列表,这是一个基本对象)。但是,当我重新创建此代码时,我发现在两个实例中都会复制:
> x <- data.frame(matrix(runif(100 * 1e4), ncol = 100))
> medians <- vapply(x, median, numeric(1))
>
> for(i in 1:5) {
+ x[, i] <- x[, i] - medians[i]
+ print(c(address(x), refs(x)))
+ }
[1] "0x10e4e6770" "2"
[1] "0x10e46c420" "2"
[1] "0x121110180" "2"
[1] "0x11c2c26d0" "2"
[1] "0x121151db0" "2"
> x <- data.frame(matrix(runif(100 * 1e4), ncol = 100))
> medians <- vapply(x, median, numeric(1))
> y <- as.list(x)
>
> for(i in 1:5) {
+ y[[i]] <- y[[i]] - medians[i]
+ print(c(address(y), refs(y)))
+ }
[1] "0x132aea2b0" "2"
[1] "0x1211839e0" "2"
[1] "0x11c237ea0" "2"
[1] "0x121169a80" "2"
[1] "0x10993f460" "2"
看来Hadley在他的例子中至少使用了R 3.1.0,而我正在使用R 3.1.2(在Mac上)。然而,我读过的所有内容都表明随着时间的推移,R的记忆管理越来越好,而上述结果表明它的情况越来越糟。虽然我可能会做一些愚蠢或误解的事情。任何人都可以向我灌输为什么我的复制与Hadley的例子没有相同的记忆效率吗?
答案 0 :(得分:2)
正如当前在pryr的CRAN版本中实现的那样,当在当前R中运行时,address()函数会将其参数的引用数量增加到2.一旦发生这种情况,就必须复制该对象以进行替换调用。 refs()函数实现避免添加引用,因此如果您只是打印refs(y),您将看到它保持为1并且不会重复。
答案 1 :(得分:0)
这不是您问题的直接答案,但我认为您的脚本可能会误导您。更改列表和data.frame的地址并不意味着所有数据的副本。
R中的 list
和data.frame
是R对象的向量。在您的脚本中,R应该只复制替换的R对象,因此更改列表的地址。
例如:
x <- data.frame(matrix(runif(100 * 1e4), ncol = 100))
medians <- vapply(x, median, numeric(1))
for(i in 1:5) {
print(sprintf("===%d===", i))
for(j in 1:5) print(sprintf("%s(%d)", address(x[[j]]), j))
x[, i] <- x[, i] - medians[i]
print(c(address(x), refs(x)))
for(j in 1:5) print(sprintf("%s(%d)", address(x[[j]]), j))
}
y <- as.list(x)
for(i in 1:5) {
print(sprintf("===%d===", i))
for(j in 1:5) print(sprintf("%s(%d)", address(y[[j]]), j))
y[[i]] <- y[[i]] - medians[i]
for(j in 1:5) print(sprintf("%s(%d)", address(y[[j]]), j))
}
您应该看到每次迭代中只更改了1个地址。赋值<-
仅复制相应R对象的数据,即x[[i]]
和y[[i]]
。不会复制4个左对象。