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


86

我正在尝试在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)
}

1
这个问题可能暗示options(expressions = somethinglarge)
mnel

@mnel表达式嵌套深度,指针保护堆栈和C堆栈是三个独立的(但相关的)东西。
zwol

非常感谢您的迅速答复,扎克。我认为您的答案可能是针对Linux操作系统的?我当前正在运行Windows 7 64位,这是否会根本改变一切?再次感谢任何帮助。
user2045093

2
对错误消息进行谷歌搜索显示,过去这通常是用户代码中的错误,因此您应该将问题简化为一个简单的可重现示例,然后将其张贴在此处。
马丁·摩根

2
我不确定代码中是否有错误。这只是概率的一种情况,理论上可能以无限递归结束。f(1,1)基本上是在掷硬币。它可能会永远出现。对于递归级别未知且不受限制的情况,最好使用以前的sample()结果的备注来通知将来的操作,以提供更多的迭代性。然后,唯一的风险就是向量内存或磁盘用完了,具体取决于要存储结果的积压位置。递归可能既昂贵又脆弱。
罗伯·凯西

Answers:


56

堆栈大小是一个操作系统参数,可按进程调整(请参阅参考资料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启动文件中,以便在您每次登录时都会执行该命令。我无法给出更具体的说明,因为它完全取决于您拥有的外壳和所用的东西。我也不知道如何登录图形环境(如果您不在终端窗口中运行R,这将是相关的)。


12
...或将其设置为unlimited
Paul Hiemstra 2013年

1
RAppArmor软件包提供了的接口setrlimit(2)ulimit某些时候该功能可能会在包装中提供。
krlmlr

2
RAppArmor软件包中不再存在此功能。有什么想法吗?
CoderGuy123

2
Windows的修复程序是什么?
S.Perera '18

2
更改限制将无法解决此问题。递归函数将简单地继续运行,直到达到上限。
汤姆·凯利

27

我怀疑,不管堆栈限制如何,您最终都会获得太深的递归。例如,对于lambda = Inf,f(1)无限期地导致立即递归。递归的深度似乎是一个随机游动,有一些可能性r会更深,1- r会完成当前递归。在达到堆栈限制时,您已经“深入”了很多步骤。这意味着r> 1/2,并且大部分时间您将继续递归。

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


1
这实际上是隐藏的正确答案-确保您不会陷入沉思...
Kamil S Jaron

就我而言,该错误是由于在项目中多次(即在多个R脚本中)采购相同的R脚本引起的。
善意

14

此错误不是由于内存,而是由于递归。函数正在调用自身。为了说明这一点,这是两个相互调用的函数的最小示例:

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太接近限制

这些函数将继续递归调用,理论上将永远不会完成。只有系统内的检查才能防止这种情况无限期地发生,并避免消耗计算机的所有计算资源。您需要更改函数以确保它们不会递归调用自己(或彼此调用)。


10

发生这种情况的原因完全不同。我在合并两列时意外创建了一个超长字符串:

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 = "_"))

永远让我想办法解决这个问题,因为我从未想到粘贴会导致问题。


同样在这里,但我正在做一个总结。我是这样的: summarize( states = paste0(state,collapse=', ') )。当我应该做的是这样的:summarize( states = paste0(sort(unique(state)),collapse=', ') )。目标是获得逗号分隔的每个子组可用的唯一状态列表。
理查德·迪萨尔沃

4

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

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

希望这对您也有帮助。


1
我切换到R的更高版本。它曾经工作过,但是错误再次出现并且现在是一致的。救命!
murphy1310 '18

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=) ?

1

对于所有人的信息,我突然在Windows 7(64位)上的R 3.6.1中遇到了这一问题。以前这不是问题,现在当我尝试“保存(。)”数据甚至执行“ save.image(。)”时,堆栈限制似乎随处可见。就像序列化将这些堆栈吹走了。

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


1

我的情况也许是一个更独特的案例,但可能会帮助有这个确切问题的少数人:

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

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

saveRDS()

但是,
偶然地,这个定义的函数被调用saveRDS()而不是safe_saveRDS()
因此,超过该定义后,当代码实际使用到wihch时saveRDS(...)(调用原始基本版本,而不是升级版本)时,它给出了以上错误并被粉碎。

因此,如果在调用某些保存功能时遇到该错误,请查看是否没有意外地运行它。


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)
}

0

引起相同问题的另一种方法:

library(debug)
mtrace(lapply)

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


0

如果您使用plot_ly,请检查要传递的列。似乎对于POSIXdt / ct列,必须先使用as.character(),然后再传递给plotly否则您将获得此异常!


0

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.