为什么一个环境的 `object.size` 比环境中 objects 的 `object.size` 小?

Why is the `object.size` of an environment smaller than the `object.size` of the objects in the environment?

我 运行 在编写函数工厂时遇到了困惑。我有一个带有识别信息列的标题,以及一个包含数据的列表列。

tib <-
    tibble(
        id_1 = letters[1:3],
        id_2 = LETTERS[1:3],
        data = list(mtcars, iris, volcano)
    )

我创建了一个函数工厂,以便轻松获取存储在此 tibble 中的数据集。

data_getter <- function(data) {
    force(data)
    function(id_1, id_2) {
        where <- data$id_1 == id_1 & data$id_2 == id_2
        data[where, ]$data %>% 
            purrr::flatten_df()
    }
}

get_from_tib <- data_getter(tib)

实际上,我正在使用的数据框非常大。我的理解是 get_from_tib 捕获包含 tib 的环境。当我这样做时,我担心通过复制这个大数据集,我会开始 运行 内存不足。然而,当我的函数的 object.size 小于它应该捕获的数据集时,我感到非常惊讶!

object.size(tib)
21752 bytes

object.size(get_from_tib)
8416 bytes

即使我从工作环境

中删除tib,这仍然有效
rm(tib)

object.size(get_from_tib)
8416 bytes

为什么环境变小了? object.size 只是获取环境中包含的所有 objects 大小的错误函数吗?

下面的 Reprex

library(magrittr)

tib <-
    dplyr::tibble(
        id_1 = letters[1:3],
        id_2 = LETTERS[1:3],
        data = list(mtcars, iris, USArrests)
    )


data_getter <- function(data) {
    force(data)
    function(id_1, id_2) {
        where <- data$id_1 == id_1 & data$id_2 == id_2
        data[where, ]$data %>% 
            purrr::flatten_df()
    }
}

get_from_tib <- data_getter(tib)

get_from_tib('c', 'C')
#> # A tibble: 50 x 4
#>    Murder Assault UrbanPop  Rape
#>     <dbl>   <int>    <int> <dbl>
#>  1   13.2     236       58  21.2
#>  2   10       263       48  44.5
#>  3    8.1     294       80  31  
#>  4    8.8     190       50  19.5
#>  5    9       276       91  40.6
#>  6    7.9     204       78  38.7
#>  7    3.3     110       77  11.1
#>  8    5.9     238       72  15.8
#>  9   15.4     335       80  31.9
#> 10   17.4     211       60  25.8
#> # … with 40 more rows


object.size(tib)
#> 21752 bytes
object.size(get_from_tib)
#> 8416 bytes


rm(tib)
object.size(get_from_tib)
#> 8416 bytes

reprex package (v0.2.1)

于 2019-04-30 创建

这与 ?object.size 帮助页面中的

部分有关

Associated space (e.g., the environment of a function and what the pointer in a EXTPTRSXP points to) is not included in the calculation.

data 变量在闭包中被捕获;它并不是 "in" 从 data_getter.

返回的函数代码

pyry::object_size() 函数在考虑封闭环境方面做得更好。

pryr::object_size(tib)
# 21 kB
pryr::object_size(get_from_tib)
# 26.9 kB