RStudio创建大型环境对象触发protect(): protection stack overflow报错咨询
RStudio创建大型哈希环境时触发protect()栈溢出错误
问题背景
我需要创建一个大型键值对查找表,尝试用如下代码实现:
# 实际使用场景下长度约为500万 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) # 问题是否出在这里? } d <- make_dict(key, val)
问题现象
运行make_dict函数时会抛出Error: protect(): protection stack overflow错误。该问题仅在RStudio中输入向量长度大于49991时出现,和同类fread报错的触发场景高度相似。
但我运行取值函数提取部分值验证时,发现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)) # 打乱键的顺序测试 anyNA(out) | !lobstr::obj_size(out) == lobstr::obj_size(val) [1] FALSE
相同代码在RGui中运行不会抛出该错误。
异常特征
- 当环境大小超过5万时,
d环境对象不会显示在RStudio的环境面板中 - R控制台快速返回>提示符(说明函数已运行完成),但报错前控制台处于无响应状态
- 无论手动设置
options(expressions = 5e5),还是保留默认值5000,均会触发报错 - 报错的触发时间与输入向量的大小正相关
tryCatch(make_dict(key, val), error = function(e) e)无法捕获该错误- 从包中运行该代码也会触发报错
咨询问题
该报错的成因是什么?如何排查这类错误?
按照通用调试教程建议设置options(error = traceback)未返回任何结果。在make_dict函数的list2env后插入browser(),浏览器打开很久后才会抛出错误。traceback()结果指向函数.rs.describeObject,该函数用于生成环境面板的对象摘要,相关代码如下:
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)
内容的提问来源于stack exchange,提问作者Donald Seinen
相关产品推荐
相关产品推荐

