首页 文章

R不使用可用的堆栈大小,返回“错误:节点堆栈溢出”

提问于
浏览
1

我在R中编写了一个递归代码 . 在调用R之前,我在shell中将堆栈大小设置为96 MB:

ulimit -s 96000

我调用R,最大保护指针堆栈大小为500000:

R --max-ppsize 500000

我将最大递归深度更改为500000:

options(expression = 500000)

我在Arch Linux存储库中使用了二进制R包(没有内存分析),也使用了内存分析选项编译的二进制文件 . 两者都是版本3.4.2

我使用了两个版本的代码,有和没有gc() .

问题是R退出代码时出现“节点堆栈溢出”错误,而使用的总可用堆栈只有16 MB,深度仅低于5e5表达式选项的1%:

size    current  direction eval_depth
  93388800   16284704          1       4958

Error: node stack overflow

最后两次迭代之间的当前堆栈使用量变化大约为10K . 唯一传递和保存的对象是19个项目的数字向量 .

代码的递归部分如下:

network_recursive <- function(called)
{
    print(Cstack_info())
    callers <- list_caller[[called + 1]] # get the callers of the called
    callers <- callers[!bool[callers + 1]] # subset for nofriends - new friends
    new_friend_no <- length(callers) # number of new friends
    print(list(called, callers) )
    if (new_friend_no > 0) # if1 still new friends
    {
        friends <<- friends + new_friend_no # increment friend no
        print(friends)
        bool[callers + 1] <<- T # toggle friends
        sapply(callers, network_recursive) # recurse network control
    } # close if1
    print("end of recursion")
}

堆栈溢出的原因是什么?

关于R源代码的一些注意事项,与问题有关 .

触发错误的代码部分是来自src / main / eval.c的第5987-5988行:

5975 #ifdef USE_BINDING_CACHE
5976   if (useCache) {
5977       R_len_t n = LENGTH(constants);
5978 # ifdef CACHE_MAX
5979       if (n > CACHE_MAX) {
5980       n = CACHE_MAX;
5981       smallcache = FALSE;
5982       }
5983 # endif
5984 # ifdef CACHE_ON_STACK
5985       /* initialize binding cache on the stack */
5986       vcache = R_BCNodeStackTop;
5987       if (R_BCNodeStackTop + n > R_BCNodeStackEnd)
5988       nodeStackOverflow();
5989       while (n > 0) {
5990       SETSTACK(0, R_NilValue);
5991       R_BCNodeStackTop++;
5992       n--;
5993       }
5994 # else
5995       /* allocate binding cache and protect on stack */
5996       vcache = allocVector(VECSXP, n);
5997       BCNPUSH(vcache);
5998 # endif
5999   }
6000 #endif

2 回答

  • 0

    节点堆栈有自己的限制,这是固定的(在Defn.h中定义, R_BCNODESTACKSIZE ) . 如果您有一个限制太小的真实示例,请提交错误报告,我们可以增加它或者为它添加命令行选项 . "node stack"由字节码解释器使用,它解释字节码编译器产生的字节码 . Cstack_info() 不显示节点堆栈使用情况 . 节点堆栈未在C堆栈上分配 .

    无论如何,基于深度递归的程序在R中都会非常慢,因为函数调用非常昂贵 . 出于实际目的,当达到与递归深度相关的限制时,重写程序以避免递归而不是增加限制可能更好 .

    就像一个实验一样,人们可能会禁用即时编译器,从而减少节点堆栈上的压力 . 它不会被完全消除,因为默认情况下已经在安装时编译了一些软件包,包括基础软件包和推荐的软件包,例如, sapply 已编译 . 另外,这可能会增加递归消除表达式的压力,程序运行速度会更慢 .

  • 1

    在我的脑海中,我看到你使用了选项(表达式= 500000),但是“options()”返回的列表中的字段被称为“表达式”(带有s) . 如果您按照问题中描述的方式键入,则“表达式”字段保持为5000,而不是您打算将其设置为500000 . 所以这可能就是为什么你只使用你认为是堆栈深度的1%时最大化的原因 .

相关问题