gpt4 book ai didi

r - 如何找到未存储在 .GlobalEnv 中的重物?

转载 作者:行者123 更新时间:2023-12-03 09:32:37 24 4
gpt4 key购买 nike

我试图找出哪些对象在我的 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 月 3 日创建

最佳答案

我认为没有任何现有的方法可以做到这一点。如果您将@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
创建于 2020-11-03 由 reprex package (v0.3.0)
我不知道为什么这些方法表会这么大(我怀疑是因为 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com