2017-11-27 12 views
1

IはRを呼び出す前R. に再帰コードを書かれている、私はシェルで96 MBにスタックサイズを設定:利用可能なスタックサイズをRで使用されていない、復帰「エラー:ノードスタックオーバーフロー」

ulimit -s 96000 

私は500000の最大保護ポインタのスタックサイズとR呼び出さ:

R --max-ppsize 500000 

私は500000に最大再帰の深さを変更:

options(expression = 500000) 

私は両方ともArch Linuxリポジトリ(メモリプロファイリングなし)でバイナリRパッケージを使用しました。また、メモリプロファイリングオプション付きで私がコンパイルしたバイナリも使用しました。どちらもバージョン3.4.2です

gc()の有無にかかわらず、2つのバージョンのコードを使用しました。

問題は、利用可能な総スタック93のMBのわずか16 MBは使用され、深さはちょうど5E5の式オプションの1%未満であるている間にR「はノードスタックオーバーフロー」エラーでコードを終了することである:

 size current direction eval_depth 
    93388800 16284704   1  4958 

Error: node stack overflow 

最後の2回の繰り返しの間の現在のスタック使用率の変化は約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 /メイン/ 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 

答えて

1

私の頭の上オフ(表現= 500000)、 "options()"によって返されるリスト内のフィールドは「式」と呼ばれます(sとともに)。あなたの質問に記載されている方法でそれを入力した場合、 '表現'フィールドは、それを設定しようとした500000ではなく5000にとどまりました。だから、スタックの深さの1%だと思ったものだけを使用していたのです。

+0

はい、それは 'expressions'です。誤って間違ってバージョンをコピーしないように質問を修正するとよいでしょう。ただし、式の数の制限ではなく、ノード・スタック・サイズの制限がヒットしています。 –

0

ノードスタックには独自の制限があります(Defn.hで定義されています、R_BCNODESTACKSIZE)。制限が小さすぎる実際の例がある場合は、バグレポートを提出してください。増やすか、コマンドラインオプションを追加することもできます。 「ノードスタック」は、バイトコードコンパイラによって生成されたバイトコードを解釈するバイトコードインタプリタによって使用されます。 Cstack_info()はノードスタックの使用状況を表示しません。ノードスタックはCスタックに割り当てられません。

関数呼び出しがかなり高価であるため、深い再帰に基づくプログラムはRで非常に遅くなります。実用的な目的のために、再帰深度に関連する限界に達すると、制限を増やすのではなく、再帰を避けるためにプログラムを書き直すほうがよいかもしれません。

ちょうど実験のようにジャストインタイムコンパイラを無効にして、それによってノードスタックの負荷を軽減するかもしれません。いくつかのパッケージは基本パッケージと推奨パッケージを含め、デフォルトでインストール時に既にコンパイルされているので、完全に削除されるわけではありません。 sapplyがコンパイルされます。また、これは反復的に除去された式のストレスを増加させる可能性があり、プログラムはさらに遅く実行されることがあります。

関連する問題