Помилка: використання стека C занадто близько до межі


86

Я намагаюся запустити якийсь досить глибокий рекурсивний код у R, і він продовжує видавати мені цю помилку:

Помилка: використання стека C занадто близько до межі

Мій результат із CStack_info():

Cstack_info()
    size    current  direction eval_depth 
67108864       8120          1          2 

На моїй машині достатньо пам’яті, я просто намагаюся зрозуміти, як я можу збільшити CStack для R.

EDIT: Хтось попросив відтворюваний приклад. Ось декілька основних зразків коду, які спричиняють проблему. Запустивши 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

Щиро дякую за Вашу оперативну відповідь, Зак. Я думаю, що ваша відповідь може бути для ОС Linux? Зараз я працюю під керуванням Windows 7 64 bit, чи це взагалі змінює ситуацію? Ще раз спасибі за будь-яку допомогу.
user2045093

2
Погугливши повідомлення про помилку, видно, що раніше це зазвичай була помилка в коді користувача, тому вам, мабуть, слід звести проблему до простого відтворюваного прикладу та опублікувати тут.
Martin Morgan

2
Я не впевнений, що в коді взагалі є помилка. Це просто випадок ймовірностей, які теоретично можуть закінчитися нескінченною рекурсією. f (1,1) в основному гортає монету. Це могло продовжувати з’являтися головами назавжди. Для стану, коли рівень рекурсії невідомий і необмежений, краще придумати щось більш ітеративне, використовуючи запам'ятовування результатів попередньої вибірки () для інформування про майбутні операції. Тоді єдиним, на що ви ризикуєте, є вичерпання векторної пам’яті або диска, залежно від того, де ви зберігаєте відставання результатів. Рекурсія може бути дорогою і крихкою.
Роберт Кейсі,

Відповіді:


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.
Paul Hiemstra,

1
RAppArmorПакет пропонує інтерфейс setrlimit(2). Ця функціональність може стати доступною в ulimitпакеті в якийсь момент.
krlmlr

2
Ця функція більше не існує в пакеті RAppArmor . Будь-які ідеї, куди це ділося?
CoderGuy123

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

2
Зміна ліміту це не вирішить. Рекурсивна функція буде просто продовжувати працювати до досягнення верхньої межі.
Том Келлі,

27

Я підозрюю, що, незалежно від обмеження стека, ви отримаєте занадто глибокі рекурсії. Наприклад, з лямбда = Inf, f (1) призводить до негайної рекурсії, на невизначений час. Глибина рекурсії здається випадковою прогулянкою, з деякою ймовірністю r заглиблення, 1 - r закінчення поточної рекурсії. На той момент, коли ви досягли межі стека, ви зробили велику кількість кроків "глибше". Це означає, що r> 1/2, і дуже велика частина часу ви просто продовжуватимете повторюватися.

Крім того, здається, що майже можливо отримати аналітичне або принаймні числове рішення навіть в умовах нескінченної рекурсії. Можна визначити p як імовірність того, що f (1) == 1, записати неявні вирази для станів "дочірнього" після однієї ітерації, прирівняти їх до p і вирішити. Потім p можна використовувати як шанс на успіх в одному витягуванні з біноміального розподілу.


1
ось насправді прихована правильна відповідь - переконайтесь, що ви не заглиблюєтесь у це ...
Kamil S Jaron

У моєму випадку помилка спричинена тим, що у моєму проекті кілька разів (тобто в декількох сценаріях R) використовується один і той же сценарій R.
Good Will

14

Ця помилка не через пам’ять, а через рекурсію . Функція викликає себе. Для ілюстрації суті, ось мінімальний приклад 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 занадто близько до межі

Функції будуть продовжувати викликати одна одну рекурсивно і теоретично ніколи не будуть завершені. Тільки перевірки у вашій системі запобігають такому нескінченному виникненню та споживанню всіх обчислювальних ресурсів вашої машини. Вам потрібно змінити функції, щоб переконатися, що вони не викликають себе (або одна одну) рекурсивно.


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

Я зіткнувся з тією ж проблемою отримання помилки "Використання стека занадто близько до межі" (хоча для іншої програми, ніж заявлена ​​користувачем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

Моє, можливо, більш унікальний випадок, але може допомогти небагатьом, хто має саме цю проблему:

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

У мене була визначена функція, яка є оновленням базової функції:

saveRDS ()

Але,
випадково, цю визначену функцію викликали saveRDS()замість safe_saveRDS().
Таким чином, минуле цього визначення, коли код потрапив у рядок, який насправді використовує wihch 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 () перед переходом до інтуїтивно, або ви отримаєте цей виняток!


0

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

Якщо це причина, рішення просто: прокоментуйте рядок.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.