我试图在我的R session 中查找哪些对象占用了大量内存,但是问题是该对象可能是在未知环境中以不知名名称创建的。
如果对象存储在.GlobalEnv或已知环境中,我可以轻松使用ls(enviro)+get()+object.size()这样的策略(例如,参见this post上的lsos)列出所有对象及其大小,从而使我能够识别较重的对象。
但是,有问题的对象可能不会存储在.GlobalEnv中,而是可能在由外部包隐式创建的一些晦涩的环境中。在那种情况下,如何确定哪个对象正在使用大量RAM?
最好的案例研究是ggplot2在专用环境中创建.last_plot。深入研究一下,您会发现它存储在environment(ggplot2:::.store$get)中,因此人们可以找到它并最终将其删除。但是,如果我不知道该位置或先验名称,是否有办法找到内存中某个重物.last_plot

pryr::mem_used()
#> 34.7 MB

## example: implicit creation of heavy and hidden object by ggplot
path <- tempfile()
if(!file.exists(path)){
  saveRDS(as.data.frame(matrix(rep(1,1e07), ncol=5)), path)
}

pryr::mem_used()
#> 34.9 MB
p1 <- ggplot2::ggplot(readr::read_rds(path), ggplot2::aes(V1))
rm(p1)
pryr::mem_used()
#> 127 MB

## Hidden object is not in .GlobalEnv
ls(.GlobalEnv, all.names = TRUE)
#> [1] "path"

## Here I know where to find it: environment(ggplot2:::.store$get)
ls(all.names = TRUE, envir = environment(ggplot2:::.store$get))
#> [1] ".last_plot"

pryr::object_size(get(".last_plot", environment(ggplot2:::.store$get))$data)
#> 80 MB

## But how could I have found this otherwise?
reprex package(v0.3.0)创建于2020-11-03

最佳答案

我认为没有任何现成的方法可以做到这一点。如果您将@AllanCameron的答案与我的评论相结合,那么您还将在ls(y)上为计算为的y环境运行

ns <- loadedNamespaces()
for (x in ns) {
   y <- loadNamespace(x)
   # look at the size of everything in y
}
您仍然找不到所有的环境。我认为如果您还检查了每个可能包含对环境的引用的对象(例如,每个函数,公式,列表和各种奇异对象),您都可以做到,但是不丢失或重复计算某件事会很棘手。
编辑添加:实际上,pryr::object_size在报告附加到对象的环境方面非常聪明,因此我们可以通过搜索 namespace 来接近。例如,要查找前20个对象:

pryr::mem_used()
#> Registered S3 method overwritten by 'pryr':
#>   method      from
#>   print.bytes Rcpp
#> 35 MB
path <- tempfile()
if(!file.exists(path)){
  saveRDS(as.data.frame(matrix(rep(1,1e07), ncol=5)), path)
}
pryr::mem_used()
#> 35.2 MB
p1 <- ggplot2::ggplot(readr::read_rds(path), ggplot2::aes(V1))
rm(p1)
pryr::mem_used()
#> 127 MB
envs <- c(globalenv = globalenv(),
          sapply(loadedNamespaces(), function(ns) loadNamespace(ns)))
sizes <- lapply(envs, function(e) {
                        objs <- ls(e, all = TRUE)
                        sapply(objs, function(obj) pryr::object_size(get(obj, envir = e)))
                })
head(sort(unlist(sizes), decreasing = TRUE), 20)
#>       base..__S3MethodsTable__.      utils..__S3MethodsTable__.
#>                        96216872                        83443704
#>       grid..__S3MethodsTable__.    ggplot2..__S3MethodsTable__.
#>                        80945520                        80636768
#>                  ggplot2..store             methods..classTable
#>                        80418936                        10101152
#>   graphics..__S3MethodsTable__.           tools..check_packages
#>                         9325608                         5185880
#>         compiler.inlineHandlers           methods..genericTable
#>                         3444600                         2808440
#>         Rcpp..__T__show:methods   colorspace..__T__show:methods
#>                         2474672                         2447880
#>                 Rcpp..RcppClass Rcpp..__C__C++OverloadedMethods
#>                         2127584                         1990504
#>            Rcpp..__C__RcppClass             Rcpp..__C__C++Field
#>                         1982576                         1980176
#>       Rcpp..__C__C++Constructor               Rcpp..__T__$:base
#>                         1979992                         1939616
#>         tools..install_packages               Rcpp..__C__Module
#>                         1904032                         1899872
reprex package(v0.3.0)创建于2020-11-03
我不知道为什么这些方法表这么大(我怀疑这是因为ggplot2向这些表添加了方法,所以它的环境被捕获了);但是他们以某种方式找到了您的对象,因为如果我不创建它们,它们就不会很大。
关于此问题的提示在第5个对象中,列为ggplot2..store (即.store命名空间中名为ggplot2的对象)。不会告诉您在.store中查看函数的环境,但是至少可以帮助您入门。
第二编辑:
这里有一些调整,使输出更具可读性。
# Unlist first, so we can clean up the names
sizes <- unlist(sizes)

# Replace the first dot with :::
names(sizes) <- sub(".", ":::", names(sizes), fixed = TRUE)

# Remove internal R objects
keep <- !grepl(".__", names(sizes), fixed = TRUE)
sizes <- sizes[keep]
经过这些更改,sort(sizes[keep], decreasing = TRUE)的输出开始为
                ggplot2:::.store
                        80418936
            base:::.userHooksEnv
                        47855920
                 base:::.Options
                        45016888
                   utils:::Rprof
                        44958416

关于r - 如何查找未存储在.GlobalEnv中的重物?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64670031/

10-12 17:17