12

繊維は私にとって比較的新しい概念です。各ファイバーのスタック サイズが 4kB に制限されていることを認識しており、これに「注意」する必要があることを読み続けています。この制限の実際の結果は正確には何ですか?

編集:

結局、この 4kB の制限はそれほど障害にはならないようで、SystemStackError を発生させるにはファイバー自体の内部にかなりの数 (4,045) のローカル変数が必要です。

count = 0
loop do
  count += 1
  puts count
  varlist = String.new
  count.times do |i|
    varlist += "a#{i} = 1\n"
  end
  s = "fiber = Fiber.new do \n #{varlist} \n end \n fiber.resume"
  eval(s)
end

最も洗練されたコードではありませんが、ファイバーのスタックの限界を示しているようです。戻り値、ローカル変数 (すべてヒープ上のオブジェクトへの参照を含む)、およびメソッド呼び出しだけがスタックに置かれるようです。ファイバーから呼び出されるメソッドのローカル変数などがファイバーのスタックの一部であるかどうかはテストしていません。

編集2:

上記のコードを修正しました。呼び出されたメソッドの変数などは、ファイバーのスタックの一部になるようです。この場合、メソッド自体が変数 (ヒープ上のオブジェクトへの透過的な参照であるように思われる) よりも多くのスペースをスタック上に必要とする可能性が高いため、呼び出しの深さ (再帰がなくても) がより大きな問題になる可能性があります。

次のコードは 4,031 回目の反復で失敗し、呼び出されたメソッドの変数がファイバーのスタックの一部になることを示しています。

count = 0
loop do
  count += 1
  puts count
  varlist = String.new
  count.times do |i|
    varlist += "a#{i} = 1\n"
  end
  m = "def meth\n #{varlist} \n end"
  eval(m)
  fiber = Fiber.new do
    meth
  end
  fiber.resume
end

編集3:

Rubinius 2.0 で最初のコード例を実行してみました。そのファイバーには 4kB のスタック制限がないように見えますが、約 3,500 回の反復を超えるとますます著しく遅くなり、5,000 回目の反復では平均して 1 秒あたり約 1 回の反復になります。5,100 回を少し超えた時点で実行を終了したため、RBX に制限があるかどうかはわかりません。また、RBX は MRI 1.9.3 の数倍のメモリを使用しています。

JRuby 1.7 では、ファイバーのスタック サイズが 4kB に設定されていないようです。また、ファイバーに最大スタック サイズがあるかどうかは不明です。最初のコード例の 5,000 回の反復を問題なく完了しましたが、予想どおり、JVM は数百 MB の RAM を食い尽くしました。

4

2 に答える 2

3

アントンが彼の答えで述べたように、あなたはファイバー内のメモリを大量に消費するコードです。(潜在的に)多くのメモリを消費する可能性のあるものの例:

  • 大きな文字列(つまり、適切なサイズのHTTP応答を含む文字列)
  • 再帰関数(スタックレベルが深すぎます!)
  • ストリームまたはストリームのようなオブジェクト:ストリームバッファには十分注意してください。それらが4kに近づくか超えると、非常に奇妙な動作が見られるようになります
于 2012-11-30T03:57:01.793 に答える
2

その結果、メモリ リークが発生する可能性があるため、Fiber コードのメモリにもっと注意を払う必要があります。

一部の再帰関数は問題を引き起こす可能性があります

于 2012-11-30T03:29:27.620 に答える