Ошибка: использование стека C слишком близко к пределу


86

Я пытаюсь запустить довольно глубокий рекурсивный код в R, и он продолжает давать мне эту ошибку:

Ошибка: использование стека C слишком близко к пределу

Мой вывод CStack_info():

Cstack_info()
    size    current  direction eval_depth 
67108864       8120          1          2 

У меня на машине много памяти, я просто пытаюсь понять, как можно увеличить CStack для R.

РЕДАКТИРОВАТЬ: Кто-то попросил воспроизводимый пример. Вот базовый пример кода, вызывающего проблему. Выполнив f (1,1) несколько раз, вы получите ошибку. Обратите внимание, что я уже установил --max-ppsize = 500000 и параметры (выражения = 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 06

Большое спасибо за быстрый ответ, Зак. Я думаю, что ваш ответ может быть для ОС Linux? Сейчас я использую 64-разрядную версию Windows 7, это вообще что-то меняет? Еще раз спасибо за любую помощь.
user2045093 06

2
Поиск сообщения об ошибке в Google показывает, что в прошлом это обычно была ошибка в коде пользователя, поэтому вам, вероятно, следует свести проблему к простому воспроизводимому примеру и опубликовать его здесь.
Мартин Морган

2
Я вообще не уверен, что в коде есть ошибка. Это просто случай вероятностей, которые теоретически могут привести к бесконечной рекурсии. f (1,1) по сути подбрасывает монету. Это могло продолжаться вечно. Для условий, когда уровень рекурсии неизвестен и неограничен, вам лучше придумать что-то более итеративное, используя запоминание предыдущих результатов sample () для информирования будущих операций. Тогда единственное, чем вы рискуете, - это нехватка векторной памяти или диска, в зависимости от того, где вы храните свой список невыполненных результатов. Рекурсия может быть дорогой и непростой.
Роберт Кейси

Ответы:


56

Размер стека - это параметр операционной системы, настраиваемый для каждого процесса (см. setrlimit(2)). Насколько я могу судить, вы не можете настроить его изнутри R, но вы можете настроить его из оболочки перед запуском R с помощью ulimitкоманды. Это работает так:

$ 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команду в файл запуска оболочки, чтобы она выполнялась каждый раз, когда вы входите в систему. Я не могу дать более конкретных указаний, чем это, потому что это зависит от того, какая именно оболочка у вас есть и все такое. Я также не знаю, как это сделать для входа в графическую среду (что будет актуально, если вы не запускаете R в окне терминала).


12
... или просто установите его на unlimited.
Пол Хиемстра

1
RAppArmorПакет предлагает интерфейс setrlimit(2). В ulimitкакой-то момент эта функция может стать доступной в пакете.
krlmlr

2
Эта функция больше не существует в пакете RAppArmor . Есть идеи, куда это делось?
CoderGuy123

2
Какое исправление для Windows?
S.Perera

2
Изменение лимита не решит этого. Рекурсивная функция просто продолжит работу, пока не будет достигнут более высокий предел.
Том Келли

27

Я подозреваю, что, независимо от лимита стека, вы получите слишком глубокие рекурсии. Например, при lambda = Inf, f (1) приводит к немедленной рекурсии до бесконечности. Глубина рекурсии кажется случайным блужданием, с некоторой вероятностью r углубления в глубину, 1 - r завершения текущей рекурсии. К тому времени, как вы достигли предела стека, вы сделали большое количество шагов «глубже». Это означает, что r> 1/2, и большую часть времени вы просто будете продолжать рекурсию.

Кроме того, кажется, что почти возможно получить аналитическое или, по крайней мере, численное решение даже в условиях бесконечной рекурсии. Можно определить p как вероятность того, что f (1) == 1, написать неявные выражения для «дочерних» состояний после одной итерации, приравнять их к p и решить. Затем p можно использовать как шанс на успех одного розыгрыша из биномиального распределения.


1
вот на самом деле скрытый правильный ответ - убедитесь, что вы не зашли так глубоко в отшельничестве ...
Камил С. Джарон,

В моем случае ошибка вызвана тем, что один и тот же сценарий R использовался несколько раз (т. Е. В нескольких сценариях R) в моем проекте.
Good Will

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 слишком близко к пределу» (хотя и для другого приложения, чем то, что указано пользователем2045093 выше). Я попробовала предложение zwol, но оно не сработало.

К моему собственному удивлению, я смог решить проблему, установив новейшую версию R для OS X (в настоящее время: версию 3.2.3), а также новейшую версию R Studio для OS X (в настоящее время: 0.99.840), поскольку я я работаю с R Studio.

Надеюсь, это тоже может вам помочь.


1
Я переключился на более высокую версию R. Один раз она работала, но ошибка появилась снова и теперь работает. Помогите!
murphy1310

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

Для всеобщего сведения, я внезапно сталкиваюсь с этим с R 3.6.1 в Windows 7 (64-разрядная версия). Раньше это не было проблемой, а теперь кажется, что ограничения стека появляются повсюду, когда я пытаюсь «сохранить (.)» Данные или даже сделать «save.image (.)». Это похоже на то, что сериализация сдувает эти стеки.

Я серьезно подумываю о том, чтобы вернуться к версии 3.6.0. Там не было.


1

Мой, возможно, более уникальный случай, но он может помочь тем немногим, у кого есть именно эта проблема:

Мой случай не имеет абсолютно ничего общего с использованием пространства, но R дал:
C stack usage is too close to the limit

У меня была определенная функция, которая является обновлением базовой функции:

saveRDS ()

Но,
случайно, эта определенная функция была вызвана saveRDS()вместо safe_saveRDS().
Таким образом, после этого определения, когда код дошел до строки, которую фактически использует saveRDS(...)(которая вызывает исходную базовую версию, а не обновленную), он выдал указанную выше ошибку и разбился.

Итак, если вы получаете эту ошибку при вызове какой-либо функции сохранения, посмотрите, не случайно ли вы ее переехали.


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)

Рекурсивный вызов здесь не так очевиден.


0

Если вы используете plot_ly, проверьте, какие столбцы вы передаете. Кажется, что для столбцов POSIXdt / ct вы должны использовать as.character () перед переходом к plotly, иначе вы получите это исключение!


0

Я часто включаю закомментированную source("path/to/file/thefile.R")строку в верхней части сценария R, например thefile.R, чтобы я мог легко скопировать и вставить ее в терминал, чтобы запустить его. Я получаю эту ошибку, если забываю закомментировать строку, поскольку при запуске файла запускается файл, который запускает файл, который запускает файл, ...

Если это причина, решение простое: закомментируйте строку.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.