10

.NET/Mono のスタックに適合する再帰レベルの数を確認するために、F# コードの小さな再帰ビットを作成しました。正確に 2 の累乗である場合はいつでも再帰の深さを出力するだけなので、2 倍以内の最大の深さを見つけます。

を使用して、定義された量のスタック領域を持つスレッドでコードを開始しますSystem.Threading.Thread (ThreadStart, int)。.Net では、再帰のレベルごとに約 100 バイトかかるようで、2G スタックで約 1600 万レベルを取得できます。メモリ使用量は Mono でほぼ同じですが、約 30,000 レベルしか取得できません。Thread過去に渡されるスタック サイズの値を600000増やしても、再帰の深さは増加しません。

ulimitスタック サイズの制限が 1G であると報告します。

Thread明白な説明は、大きすぎる場合、Mono は の 2 番目の引数に従わないということです。Monoに大きなスタックを割り当てるよう説得する方法を知っている人はいますか?

コードは簡単ですが、誰かが気になる場合に備えて以下に示します。

let rec f i =
    if popcount i = 1 then // population count is one on exact powers of 2
        printf "Got up to %d\n" i
        stdout.Flush ()
    if i = 1000000000 then 0 else 1 + f (i+1)
4

4 に答える 4

8

オプション 1: モノ スタック サイズを変更する

Thread明白な説明は、大きすぎる場合、Mono は の 2 番目の引数に従わないということです。Monoに大きなスタックを割り当てるよう説得する方法を知っている人はいますか?

大きな値を渡したとしても、Mono がスタック サイズを制限することは正しいです。たとえば、私の Cent OS 64 ビット テスト マシンでは、Mono が割り当てる最大スタック サイズは 2 メガバイトです。Mono C# ソース ファイル Thread.csは、 Monoスレッドを作成するとどうなるかを示しています。

パブリック スレッド (ThreadStart 開始、int maxStackSize)
{
    if (開始 == null)
        新しい ArgumentNullException ("開始") をスローします。

    スレッドスタート = 開始;
    Internal.stack_size = CheckStackSize (maxStackSize);
}

static int CheckStackSize (int maxStackSize)
{
    もし (maxStackSize < 0)
        新しい ArgumentOutOfRangeException ("ゼロ未満"、"maxStackSize") をスローします。

    if (maxStackSize < 131072) // スタックが少なくとも 128k であることを確認します
        131072 を返します。

    int page_size = Environment.GetPageSize ();

    if ((maxStackSize % page_size) != 0) // ページ サイズの割り切れる数に切り上げる
        maxStackSize = (maxStackSize / (page_size - 1)) * page_size;

    int default_stack_size = (IntPtr.Size / 4) * 1024 * 1024; // wthreads.c から
    if (maxStackSize > default_stack_size)
        default_stack_size を返します。

    maxStackSize を返します。
}

上記のコードは、スタック サイズにハード リミットを設定します。

理論的には、上記の関数 (太字の行) の一方または両方のコードを変更して、より大きなスタック サイズが割り当てられるようにすることができます。これを行ったら、Mono ランタイムをビルドし、関数を実行して、変更によって違いが生じるかどうかを確認する必要があります。

より大きなスタックを割り当てることが特定のケースで役立つかどうかを理解するのに、私は Mono について十分に知らないことを強調しておきます。これは最後の手段としてのみ行います(他の回答がどちらも機能しない場合)。

于 2013-11-11T15:03:22.137 に答える