为什么某些内存地址报告不变而其他地址发生变化

时间:2015-11-12 08:29:53

标签: r memory memory-address

我一直试图使用data.table::address.Internal(address())跟踪内存中的各种对象,但是注意到有些对象每次返回相同的地址,而其他对象几乎总是不同的。这是怎么回事?

我注意到列表(data.tables,data.frames等)等对象的地址保持不变(由这些函数报告),而如果我尝试按[报告地址进入一个列表,即address(lst[1])我几乎每次都得到不同的结果。另一方面,lst[[1]]返回相同的值,address(pi)等常量的地址保持不变,而address(1)是不稳定的。为什么会这样?

## Create some data.tables of different sizes and plot the addresses
library(data.table)
par(mfrow = c(2,2))
for (i in 2:5) {
    dat <- data.table(a=1:10^i)
    ## Constants
    addr1 <- address(dat)
    addr2 <- address(dat[[1]])
    addr3 <- address(dat$a)  # same as addr2
    ## Vary
    addrs <- replicate(5000, address(dat[1]))
    plot(density(as.integer(as.hexmode(addrs))), main=sprintf("N: %g", nrow(dat)))
    abline(v=as.integer(as.hexmode(c(addr1, addr2, addr3))), col=1:3, lwd=2, lty=1:3)
    legend("topleft", c("dat", "dat[[1]]", "dat$a"), col=1:3, lwd=2, lty=1:3)
}

以下是我用不同大小的data.tables谈论的一些例子。它们只是address(dat[1])(转换为整数)结果的密度,而这些行对应于data.table的常量地址。

enter image description here

1 个答案:

答案 0 :(得分:3)

首先,我可以复制你的结果,所以我做了一些调查,并通过一些代码潜水。

当您使用dat访问dat[1]的第一个成员时,您实际上正在创建一个由listdata[[1]]中的dat$a创建的切片。要获取切片,R首先复制列表,然后返回所需的切片。

所以 - 基本上 - 你看到你看到了什么,因为索引的[]语法返回一个包含dat 的第一个元素的切片,它是{{1}的副本},它将位于任意内存位置。

dat$a语法返回对实际列表的引用,该列表是[[]]data.table中的列,因此其地址不变(或者至少在您更改之前该名单的成员)。

这可能令人困惑,因为当然执行data.frame或类似操作会改变数据结构中列表的值。但是,如果您在进行此类更改之前和之后查看dat[1] = 6,您会注意到实际上引用现在是另一个列表(副本),例如。

address(dat[[1]])

查看> dat <- data.table(a=1:10000) > dat a 1: 1 2: 2 3: 3 4: 4 5: 5 --- 9996: 9996 9997: 9997 9998: 9998 9999: 9999 10000: 10000 > address(dat[[1]]) [1] "000000000CF389D8" > address(dat[[1]]) [1] "000000000CF389D8" > dat[1] = 100 > address(dat[[1]]) [1] "000000000D035B38" > dat a 1: 100 2: 2 3: 3 4: 4 5: 5 --- 9996: 9996 9997: 9997 9998: 9998 9999: 9999 10000: 10000 > (而不是data.frame)的源代码,执行切片索引(data.tableis here的代码,而直接索引({ {1}})is here。你可以看到后者更简单,并且长话短说,前者返回副本。如果直接更改切片(例如[]),则会有一些logic here处理,以确保数据框现在引用更新后的副本。