【问题标题】:RStudio error - creating large environment object: protect(): protection stack overflowRStudio 错误 - 创建大型环境对象:protect():保护堆栈溢出
【发布时间】:2021-12-31 01:53:08
【问题描述】:

我想创建一个大的键值对查找表,尝试如下:

# actual use case is length ~5 million
key <- do.call(paste0, Map(stringi::stri_rand_strings, n=2e5, length = 16))
val <- sample.int(750, size = 2e5, replace = T)

make_dict <- function(keys, values){
  require(rlang)
  e <- new.env(size = length(keys))
  l <- list2(!!!setNames(values, keys))
  list2env(l, envir = e, hash = T) # problem in here...?
}

d <- make_dict(key, val)

问题

make_dict 运行时,它会抛出Error: protect(): protection stack overflow。特别是在 RStudio 中,当输入是一个长度大于 49991 的向量时,这似乎与 this stackoverflow post 非常相似。

但是,当我运行访问器函数来获取一些值时,make_dict 似乎运行良好,因为我在其结果中找不到任何奇怪之处:

`%||%` <- function(x,y) if(is.null(x)) y else x
grab <- function(...){
  vector("integer", length(..2)) |>
    (\(.){. = Vectorize(\(e, x) e[[x]] %||% NA_integer_, list("x"), T, F)(..1, ..2); .})()
}
out <- vector("integer", length(key))
out <- grab(d, sample(key)) # using sample to scramble the keys

anyNA(out) | !lobstr::obj_size(out) == lobstr::obj_size(val)
[1] FALSE

在 RGui 中运行相同的代码不会引发错误。

奇事

  1. d 环境对象不会出现在 RStudio 的环境窗格中,其大小 > 5e4。
  2. R 控制台迅速返回 >(表示函数已完成),但在抛出错误之前无响应
  3. 如果manually setting options(expressions = 5e5) 或保留默认值 5000,则会引发错误
  4. 抛出错误的时间与输入向量的大小成正比
  5. tryCatch(make_dict(key, val), error = function(e) e) 没有发现错误
  6. 如果从包中运行代码也会出现该错误(打包版本可通过remotes::install_github("D-Se/minimal")获得)

问题

这里发生了什么?如何解决此类错误?

options(error = traceback) 建议 here 没有给出任何结果。在make_dict 函数中的list2env 之后插入browser() 会在浏览器打开很久后引发错误。一个traceback()给出了函数.rs.describeObject,用于generate the summary in the Environment pane,可以找到here

traceback()

# .rs.describeObject
(function (env, objName, computeSize = TRUE) 
   {
       obj <- get(objName, env)
       hasNullPtr <- .Call("rs_hasExternalPointer", obj, TRUE, PACKAGE = "(embedding)")
       if (hasNullPtr) {
           val <- "<Object with null pointer>"
           desc <- "An R object containing a null external pointer"
           size <- 0
           len <- 0
       }
       else {
           val <- "(unknown)"
           desc <- ""
           size <- if (computeSize) 
               object.size(obj)
           else 0
           len <- length(obj)
       }
       class <- .rs.getSingleClass(obj)
       contents <- list()
       contents_deferred <- FALSE
       if (is.language(obj) || is.symbol(obj)) {
           val <- deparse(obj)
       }
       else if (!hasNullPtr) {
           if (size > 524288) {
               len_desc <- if (len > 1) 
                   paste(len, " elements, ", sep = "")
               else ""
               if (is.data.frame(obj)) {
                   val <- "NO_VALUE"
                   desc <- .rs.valueDescription(obj)
               }
               else {
                   val <- paste("Large ", class, " (", len_desc, 
                     format(size, units = "auto", standard = "SI"), 
                     ")", sep = "")
               }
               contents_deferred <- TRUE
           }
           else {
               val <- .rs.valueAsString(obj)
               desc <- .rs.valueDescription(obj)
               if (class == "data.table" || class == "ore.frame" || 
                   class == "cast_df" || class == "xts" || class == 
                   "DataFrame" || is.list(obj) || is.data.frame(obj) || 
                   isS4(obj)) {
                   if (computeSize) {
                     contents <- .rs.valueContents(obj)
                   }
                   else {
                     val <- "NO_VALUE"
                     contents_deferred <- TRUE
                   }
               }
           }
       }
       list(name = .rs.scalar(objName), type = .rs.scalar(class), 
           clazz = c(class(obj), typeof(obj)), is_data = .rs.scalar(is.data.frame(obj)), 
           value = .rs.scalar(val), description = .rs.scalar(desc), 
           size = .rs.scalar(size), length = .rs.scalar(len), contents = contents, 
           contents_deferred = .rs.scalar(contents_deferred))
   })(<environment>, "d", TRUE)

【问题讨论】:

    标签: r dictionary error-handling rstudio


    【解决方案1】:

    @technocrat 指出的 github issue 谈到了 RStudio 早期版本中的一个已知错误,即禁用 空外部指针检查,此后已通过在 @987654322 中添加额外的首选项检查来解决@的

    .rs.readUiPref("check_null_external_pointers")
    

    要检查代码是否从 RStudio 内部运行,如果该版本低于某个版本号之前的版本(这里我使用当前的官方版本),可以在函数中包含检查,或者在 @ 987654324@一包:

    if(!is.na(Sys.getenv("RSTUDIO", unset = NA)) && .rs.api.versionInfo()$version < "2021.9.1.372")){
      # warning or action
    }
    

    【讨论】:

      猜你喜欢
      • 2016-06-30
      • 1970-01-01
      • 2023-04-07
      • 2014-07-03
      • 1970-01-01
      • 1970-01-01
      • 2015-06-17
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多