Błąd: użycie stosu C jest zbyt bliskie limitowi


86

Próbuję uruchomić jakiś dość głęboki kod rekurencyjny w R i ciągle daje mi ten błąd:

Błąd: użycie stosu C jest zbyt bliskie limitowi

Moje wyniki z CStack_info()to:

Cstack_info()
    size    current  direction eval_depth 
67108864       8120          1          2 

Mam dużo pamięci na moim komputerze, próbuję tylko dowiedzieć się, jak mogę zwiększyć CStack dla R.

EDYCJA: Ktoś poprosił o powtarzalny przykład. Oto kilka podstawowych przykładowych kodów, które powodują problem. Kilkakrotne uruchomienie f (1,1) spowoduje wyświetlenie błędu. Zauważ, że już ustawiłem --max-ppsize = 500000 i opcje (wyrażenia = 500000), więc jeśli ich nie ustawisz, możesz otrzymać błąd dotyczący jednej z tych dwóch rzeczy. Jak widać, rekurencja może tu sięgać dość głęboko i nie mam pojęcia, jak sprawić, by działała konsekwentnie. Dzięki.

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
To pytanie sugeruje być możeoptions(expressions = somethinglarge)
mnel

@mnel Wyrażenie głębokość zagnieżdżenia, stos ochrony wskaźnika i stos C to trzy oddzielne (ale powiązane) rzeczy.
zwol

Dziękuję bardzo za twoją szybką odpowiedź, Zack. Myślę, że twoja odpowiedź może dotyczyć systemu operacyjnego Linux? Obecnie używam 64-bitowego systemu Windows 7, czy to w ogóle coś zmienia? Jeszcze raz dziękuję za wszelką pomoc.
user2045093

2
Wygooglowanie komunikatu o błędzie pokazuje, że w przeszłości był to zwykle błąd w kodzie użytkownika, więc prawdopodobnie powinieneś ograniczyć problem do prostego, odtwarzalnego przykładu i opublikować go tutaj.
Martin Morgan,

2
Nie jestem pewien, czy w ogóle jest błąd w kodzie. Jest to po prostu przypadek prawdopodobieństw, które w teorii mogłyby zakończyć się nieskończoną rekurencją. f (1,1) to po prostu rzucanie monetą. Mógłby pojawiać się w głowach na zawsze. W przypadku warunku, w którym poziom rekurencji jest nieznany i nieograniczony, lepiej wymyślić coś bardziej iteracyjnego, używając zapamiętywania poprzednich wyników sample () do informowania o przyszłych operacjach. Wtedy jedyną rzeczą, którą ryzykujesz, jest brak pamięci wektorowej lub dysku, w zależności od tego, gdzie przechowujesz swoje zaległości w wynikach. Rekursja może być kosztowna i krucha.
Robert Casey,

Odpowiedzi:


56

Rozmiar stosu to parametr systemu operacyjnego, regulowany dla każdego procesu (zobacz setrlimit(2)). Nie możesz dostosować go z poziomu R, o ile wiem, ale możesz go dostosować z powłoki przed uruchomieniem R za pomocą ulimitpolecenia. Działa to tak:

$ ulimit -s # print default
8192
$ R --slave -e 'Cstack_info()["size"]'
   size 
8388608

8388608 = 1024 * 8192; R wypisuje tę samą wartość co ulimit -s, ale w bajtach zamiast w kilobajtach.

$ ulimit -s 16384 # enlarge stack limit to 16 megs
$ R --slave -e 'Cstack_info()["size"]'
    size 
16777216 

Aby na stałe zmienić to ustawienie, dodaj ulimitpolecenie do pliku startowego powłoki, aby było wykonywane za każdym razem, gdy się logujesz. Nie mogę podać bardziej szczegółowych wskazówek, ponieważ zależy to dokładnie od posiadanej powłoki i tak dalej. Nie wiem też, jak to zrobić, aby zalogować się do środowiska graficznego (co będzie istotne, jeśli nie używasz R w oknie terminala).


12
... lub po prostu ustaw unlimited.
Paul Hiemstra,

1
RAppArmorPakiet oferuje interfejs setrlimit(2). Ta funkcja może być w ulimitpewnym momencie dostępna w pakiecie.
krlmlr

2
Ta funkcja już nie istnieje w pakiecie RAppArmor . Jakieś pomysły, gdzie to poszło?
CoderGuy123

2
Jaka jest poprawka dla systemu Windows?
S.Perera

2
Zmiana limitu nie rozwiąże tego problemu. Funkcja rekurencyjna będzie po prostu działać, aż do osiągnięcia wyższego limitu.
Tom Kelly,

27

Podejrzewam, że niezależnie od limitu stosu, skończysz z rekurencjami, które są zbyt głębokie. Na przykład, gdy lambda = Inf, f (1) prowadzi do natychmiastowej rekursji w nieskończoność. Głębokość rekursji wydaje się być błądzeniem losowym, z pewnym prawdopodobieństwem zagłębienia się r, 1 - r zakończenia bieżącej rekursji. Zanim osiągnąłeś limit stosu, zrobiłeś wiele „głębszych” kroków. Oznacza to, że r> 1/2 i przez większość czasu będziesz po prostu kontynuować powtarzanie.

Wydaje się również, że prawie możliwe jest wyprowadzenie analitycznego lub przynajmniej numerycznego rozwiązania nawet w obliczu nieskończonej rekurencji. Można zdefiniować p jako prawdopodobieństwo, że f (1) == 1, napisać niejawne wyrażenia dla stanów „potomnych” po jednej iteracji, zrównać je z p i rozwiązać. p może być następnie użyte jako szansa powodzenia w pojedynczym losowaniu z rozkładu dwumianowego.


1
tutaj jest właściwie ukryta prawidłowa odpowiedź - upewnij się, że nie wpadniesz tak głęboko w rekultywację ...
Kamil S Jaron

W moim przypadku błąd jest spowodowany wielokrotnym pozyskiwaniem tego samego skryptu R (tj. W wielu skryptach R) w moim projekcie.
Good Will

14

Ten błąd nie jest spowodowany pamięcią, ale rekursją . Funkcja wywołuje samą siebie. Aby to zilustrować, oto minimalny przykład dwóch funkcji, które wywołują się nawzajem:

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

Błąd: użycie stosu C 7971600 jest zbyt blisko limitu

Funkcje będą nadal wywoływać się nawzajem rekurencyjnie i teoretycznie nigdy się nie zakończą. Tylko kontrole w systemie zapobiegają temu w nieskończoność i zużywaniu wszystkich zasobów obliczeniowych maszyny. Musisz zmienić funkcje, aby upewnić się, że nie wywołują siebie (lub siebie nawzajem) rekurencyjnie.


10

Przydarzyło mi się to z zupełnie innego powodu. Przypadkowo utworzyłem bardzo długi ciąg, łącząc dwie kolumny:

output_table_subset = mutate(big_data_frame,
     combined_table = paste0(first_part, second_part, col = "_"))

zamiast

output_table_subset = mutate(big_data_frame,
     combined_table = paste0(first_part, second_part, sep = "_"))

Zajęło mi to wieczność, ponieważ nigdy nie spodziewałem się, że pasta spowodowała problem.


To samo tutaj, ale robiłem podsumowanie. Miałem to tak: summarize( states = paste0(state,collapse=', ') ). Kiedy powinienem zrobić coś takiego: summarize( states = paste0(sort(unique(state)),collapse=', ') ). Celem było uzyskanie listy oddzielonych przecinkami unikalnych stanów dostępnych dla każdej podgrupy.
Richard DiSalvo

4

Napotkałem ten sam problem z otrzymaniem błędu „Użycie stosu C jest zbyt blisko limitu” (choć dla innej aplikacji niż ta podana powyżej przez user2045093). Wypróbowałem propozycję Zwol, ale nie wyszło.

Ku mojemu zdziwieniu mogłem rozwiązać problem instalując najnowszą wersję R na OS X (obecnie: wersja 3.2.3), a także najnowszą wersję R Studio na OS X (obecnie: 0.99.840), ponieważ ja pracuję z R Studio.

Miejmy nadzieję, że to również może być pomocne.


1
Przerzuciłem się na wyższą wersję R. Raz działało, ale błąd pojawił się ponownie i teraz jest spójny. Wsparcie!
murphy1310

2

Jednym z problemów może być to, że dzwonisz fdo siebie

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

Dla wszystkich informacji, nagle wpadam na to z R 3.6.1 na Windows 7 (64-bitowy). Wcześniej nie był to problem, a teraz wydaje się, że limity stosu pojawiają się wszędzie, kiedy próbuję „zapisać (.)” Dane lub nawet zrobić „save.image (.)”. To tak, jakby serializacja usuwała te stosy.

Poważnie rozważam powrót do 3.6.0. Tam się nie wydarzyło.


1

Mój przypadek jest być może bardziej wyjątkowy, ale może pomóc nielicznym, którzy mają dokładnie ten problem:

Mój przypadek nie ma absolutnie nic wspólnego z wykorzystaniem przestrzeni, ale R podał:
C stack usage is too close to the limit

Miałem zdefiniowaną funkcję, która jest aktualizacją funkcji podstawowej:

saveRDS ()

Ale,
przypadkowo, ta zdefiniowana funkcja została wywołana saveRDS()zamiast safe_saveRDS().
Tak więc, poza tą definicją, kiedy kod dotarł do wiersza, którego faktycznie używa saveRDS(...)(która wywołuje oryginalną wersję podstawową, a nie uaktualnioną), podał powyższy błąd i zgnieciony.

Jeśli więc otrzymujesz ten błąd podczas wywoływania jakiejś funkcji zapisywania, sprawdź, czy przypadkowo go nie przejechałeś.


0

Jak napisał Martin Morgan ... Problem polega na tym, że wchodzisz zbyt głęboko w rekursję. Jeśli rekurencja w ogóle nie jest zbieżna, musisz ją przerwać samodzielnie. Mam nadzieję, że ten kod zadziała, ponieważ nie jest testowany. Jednak przynajmniej punkt powinien być tutaj jasny.

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

Inny sposób spowodowania tego samego problemu:

library(debug)
mtrace(lapply)

Wywołanie rekurencyjne nie jest tutaj tak oczywiste.


0

Jeśli używasz plot_ly, sprawdź, które kolumny przechodzisz. Wygląda na to, że dla kolumn POSIXdt / ct musisz użyć as.character () przed przejściem do plotly, inaczej otrzymasz ten wyjątek!


0

Często dołączam zakomentowaną source("path/to/file/thefile.R")linię na początku skryptu R, npthefile.R Więc mogę łatwo skopiować i wkleić to do terminala, aby go uruchomić. Ten błąd pojawia się, jeśli zapomnę zakomentować wiersz, ponieważ uruchomienie pliku powoduje uruchomienie pliku, który uruchamia plik, który uruchamia plik, ...

Jeśli to jest przyczyną, rozwiązanie jest proste: zakomentuj linię.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.