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

问题描述 投票:60回答:7

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

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

我从CStack_info()的输出是:

Cstack_info()
    size    current  direction eval_depth 
67108864       8120          1          2 

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

编辑:有人要求一个可重复的例子。这是导致问题的一些基本示例代码。运行f(1,1)几次就会出现错误。请注意,我已经设置了--max-ppsize = 500000和options(表达式= 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)
}
r
7个回答
48
投票

堆栈大小是一个操作系统参数,可按进程调整(请参阅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,这将是相关的)。


16
投票

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

而且,即使在无限递归的情况下,似乎几乎可以推导出解析或至少数值解。可以将p定义为f(1)== 1的概率,在单次迭代后写入“子”状态的隐式表达式,并将它们与p等同,并求解。然后,p可以用作从二项分布中单次绘制成功的机会。


8
投票

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

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

让我永远想弄清楚,因为我从来没有想到粘贴会导致问题。


3
投票

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

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

希望这也可能对你有所帮助。


2
投票

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

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

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


1
投票

这里的一个问题可能是你在里面调用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=) ?

0
投票

正如马丁摩根写的那样......问题是你在递归中得到了太深的内心。如果递归根本没有收敛,你需要自己打破它。我希望这段代码能够正常运行,因为它没有经过测试。但至少应该明确这一点。

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)

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

© www.soinside.com 2019 - 2024. All rights reserved.