101

我试图在 R 中运行一些相当深的递归代码,它一直给我这个错误:

错误:C 堆栈使用量太接近限制

我的输出CStack_info()是:

Cstack_info()
    size    current  direction eval_depth 
67108864       8120          1          2 

我的机器上有足够的内存,我只是想弄清楚如何增加 R 的 CStack。

编辑:有人要求提供可重复的示例。这是导致问题的一些基本示例代码。运行 f(1,1) 几次你会得到错误。请注意,我已经设置了 --max-ppsize = 500000 和 options(expressions=500000) 所以如果你不设置这些,你可能会得到关于这两件事之一的错误。正如你所看到的,递归在这里可能会很深,我不知道如何让它始终如一地工作。谢谢。

f <- function(root=1,lambda=1) {
    x <- c(0,1);
    prob <- c(1/(lambda+1),lambda/(lambda+1));
        repeat {
      if(root == 0) {
        break;
      }
      else {
        child <- sample(x,2,replace=TRUE,prob);
        if(child[1] == 0 && child[2] == 0) {
          break;
        }
        if(child[1] == 1) {
          child[1] <- f(root=child[1],lambda);
        }
        if(child[2] == 1 && child[1] == 0) {
          child[2] <- f(root=child[2],lambda);
        }
      }
      if(child[1] == 0 && child[2] == 0) {
        break;
      }
      if(child[1] == 1 || child[2] == 1) {
        root <- sample(x,1,replace=TRUE,prob);
      }
        }
    return(root)
}
4

15 回答 15

62

堆栈大小是一个操作系统参数,可按进程调整(请参阅 参考资料setrlimit(2))。据我所知,您无法从 R 中对其进行调整,但是您可以在启动 R 之前使用ulimit命令从 shell 中对其进行调整。它是这样工作的:

$ ulimit -s # print default
8192
$ R --slave -e 'Cstack_info()["size"]'
   size 
8388608

8388608 = 1024 * 8192;R 正在打印与 相同的值ulimit -s,但以字节而不是千字节为单位。

$ ulimit -s 16384 # enlarge stack limit to 16 megs
$ R --slave -e 'Cstack_info()["size"]'
    size 
16777216 

要对此设置进行永久调整,请将ulimit命令添加到您的 shell 启动文件中,以便在您每次登录时执行。我无法给出更具体的指示,因为这取决于您拥有的 shell 和内容。我也不知道如何登录图形环境(如果您不在终端窗口中运行 R,这将是相关的)。

于 2013-02-06T00:20:11.127 回答
28

我怀疑,无论堆栈限制如何,您最终都会遇到太深的递归。例如,当 lambda = Inf 时,f(1) 会无限期地导致立即递归。递归的深度似乎是随机游走,有一定的概率 r 更深,1 - r 完成当前递归。当你达到堆栈限制时,你已经使大量的步骤“更深”了。这意味着 r > 1 / 2,并且大部分时间您将继续递归。

此外,即使面对无限递归,似乎也几乎可以推导出解析解或至少是数值解。可以将 p 定义为 f(1) == 1 的概率,为单次迭代后的“子”状态编写隐式表达式,并将它们与 p 等同,然后求解。然后 p 可以用作从二项分布中单次抽取的成功机会。

于 2013-02-06T07:47:53.517 回答
19

此错误不是由于内存造成的,而是由于递归造成的。一个函数正在调用自己。从只检查一个函数的定义来看,这并不总是显而易见的。为了说明这一点,这里有两个相互调用的函数的最小示例:

change_to_factor <- function(x){
  x <- change_to_character(x)
  as.factor(x)
} 

change_to_character <- function(x){
  x <- change_to_factor(x)
  as.character(x)
}

change_to_character("1")

错误:C 堆栈使用 7971600 太接近限制

这些函数将继续递归地相互调用,理论上永远不会完成,即使你增加了限制,它仍然会被超过。只有在您的系统中进行检查才能防止这种情况无限期地发生并消耗您机器的所有计算资源。您需要更改函数以确保它们不会无限期地递归调用自身(或彼此)。

于 2018-12-19T12:37:19.970 回答
12

这发生在我身上的原因完全不同。我在组合两列时不小心创建了一个超长字符串:

output_table_subset = mutate(big_data_frame,
     combined_table = paste0(first_part, second_part, col = "_"))

代替

output_table_subset = mutate(big_data_frame,
     combined_table = paste0(first_part, second_part, sep = "_"))

让我永远想通了,因为我从没想过粘贴会导致问题。

于 2015-04-22T08:21:29.523 回答
5

我遇到了同样的问题,即收到“C 堆栈使用量太接近限制”错误(尽管对于另一个应用程序,而不是上面 user2045093 所述的应用程序)。我尝试了 zwol 的建议,但没有成功。

令我惊讶的是,我可以通过安装最新版本的 R for OS X(当前:版本 3.2.3)以及最新版本的 R Studio for OS X(当前:0.99.840)来解决这个问题,因为我我正在与 R Studio 合作。

希望这对您也有一些帮助。

于 2015-12-31T16:06:15.660 回答
2

这里的一个问题可能是你在f内部调用

plop <- function(a = 2){
  pouet <- sample(a)
  plop(pouet)
}
plop()
Erreur : évaluations trop profondément imbriquées : récursion infinie / options(expressions=) ?
Erreur pendant l'emballage (wrapup) : évaluations trop profondément imbriquées : récursion infinie / options(expressions=) ?
于 2018-02-26T17:49:18.180 回答
2

我的可能是一个更独特的案例,但可能会帮助少数遇到这个确切问题的人:

我的情况与空间使用完全无关,仍然 R 给出了:
C stack usage is too close to the limit

我有一个定义的函数,它是基本函数的升级:

保存RDS()

但是,
意外的是,这个定义的函数被调用saveRDS()而不是safe_saveRDS().
因此,通过该定义,当代码到达实际使用的行saveRDS(...)(它调用原始基本版本,而不是升级版本)时,它给出了上述错误并崩溃了。

因此,如果您在调用某些保存函数时遇到该错误,请查看您是否不小心碰到了它。

于 2019-12-12T20:23:53.087 回答
1

source("path/to/file/thefile.R")我经常在 R 脚本的顶部包含一个注释掉的行,例如thefile.R,因此我可以轻松地将其复制粘贴到终端中以运行它。如果我忘记注释掉该行,我会收到此错误,因为运行文件运行文件,运行文件,运行文件,...

如果这是原因,解决方案很简单:注释掉该行。

于 2020-09-01T19:05:20.523 回答
1

在 Linux 上,我通过这样做永久增加了堆栈和 memlock 内存的大小:

sudo vi /etc/security/limits.conf 

然后,在文件末尾添加以下行。

* soft memlock unlimited
* hard memlock unlimited

* soft stack unlimited
* hard stack unlimited
于 2020-11-26T10:10:56.753 回答
1

对于大家的信息,我突然在 Windows 7(64 位)上使用 R 3.6.1 遇到了这个问题。以前这不是问题,现在当我尝试“save(.)”数据甚至执行“save.image(.)”时,堆栈限制似乎无处不在。就好像序列化正在把这些堆栈吹走。

我正在认真考虑退回到 3.6.0。那里没有发生。

于 2019-07-17T01:50:53.670 回答
0

正如 Martin Morgan 所写的那样……问题是您对递归的了解太深了。如果递归根本不收敛,你需要自己打破它。我希望这段代码能正常工作,因为它没有经过测试。但是,至少这里应该清楚一点。

f <- function(root=1,lambda=1,depth=1) {
 if(depth > 256){
  return(NA)
 }
 x <- c(0,1);
 prob <- c(1/(lambda+1),lambda/(lambda+1));
 repeat {
  if(root == 0) {
    break;
  } else {
   child <- sample(x,2,replace=TRUE,prob);
   if(child[1] == 0 && child[2] == 0) {
     break;
   }
   if(child[1] == 1) {
     child[1] <- f(root=child[1],lambda,depth+1);
   }
   if(child[2] == 1 && child[1] == 0) {
     child[2] <- f(root=child[2],lambda,depth+1);
   }
  }
  if(child[1] == NA | child[2] == NA){
   return NA;
  }
  if(child[1] == 0 && child[2] == 0) {
    break;
  }
  if(child[1] == 1 || child[2] == 1) {
    root <- sample(x,1,replace=TRUE,prob);
  }
 }
 return(root)
}
于 2015-05-12T17:56:43.827 回答
0

这是我遇到此错误消息的方式。当我尝试在控制台中打印 data.table 时遇到此错误消息。原来这是因为我错误地在列中创建了一个超长字符串(当我不应该在 paste() 中使用折叠时)。

于 2021-09-30T15:04:46.357 回答
0

导致相同问题的另一种方法:

library(debug)
mtrace(lapply)

递归调用在这里并不那么明显。

于 2019-05-23T20:49:09.657 回答
0

如果您使用 plot_ly 检查您传递的列。似乎对于 POSIXdt/ct 列,您必须在传递给 plotly 之前使用 as.character() ,否则会出现此异常!

于 2019-07-12T18:18:41.513 回答
0

不确定我们是否在这里列出问题,但它发生在我身上leaflet()。我试图映射一个数据框,其中有一date列属于 class POSIXlt。换回POSIXct解决问题。

于 2020-11-18T11:24:41.020 回答