10

このコードの何が問題になっていますか?

using System;
namespace app1
{
    static class Program
    {
        static int x = 0;
        static void Main()
        {
            fn1();
        }
        static void fn1()
        {
            Console.WriteLine(x++);
            fn1();
        }
    }
}

このコマンドを使用して、このコードをコンパイルします。

csc /warn:0 /out:app4noex.exe app4.cs

exeをダブルクリックしても、例外(StackOverFlowException)がスローされないようで、永久に実行され続けます。

Visual Studioコマンドプロンプト2010を使用していますが、システムにvs2012もインストールされています。すべて最新です。

4

4 に答える 4

10

オプティマイザは末尾再帰呼び出しを次のように展開するためです。

    static void fn1()
    {
      START:

        Console.WriteLine(x++);
        GOTO START;
    }

次のような例外を取得するように書き直します。

   static int y;

   static void fn1()
   {
       Console.WriteLine(x++);
       fn1();
       Console.WriteLine(y++);
   }
于 2012-12-29T20:51:15.410 に答える
3

x64ジッターはこれを末尾呼び出しとして検出し、最適化しますが、x86ジッターはこれを行いません。x64ジッターは、これらの最適化に対してより積極的です。BartdeSmetの分析とCLRチームのブログ投稿を参照してください。

于 2012-12-29T21:07:05.577 に答える
1

末尾再帰最適化と呼ばれるものがあります。

スタックの観点からは、基本的に、メソッドが最後に行うのが別のメソッドを呼び出すことである場合、新しい呼び出しは呼び出し元のメソッドのスタックフレームを取得できることを意味します。例:

static void Main()
{
  fn(0);
}

static void fn(int value)
{
   fn(value+1);
}

コールスタックがMain->fn(0)->fn(1)->...ひどく大きくなる代わりに、それはちょうど2つのリンクの長さであり、最初Main->fn(0)Main->fn(1)Main->fn(int.MaxValue)それが爆発するかオーバーフローするところまでです。

さて、問題は、C#コンパイラが実際にこれを行うのかということです。
AFAIK、4.0以降のC#コンパイラを使用して、x86環境でコンパイルする場合は末尾呼び出しの最適化を使用せず、x64アプリケーションをコンパイルする場合は末尾呼び出しの最適化を使用ます(明らかに、他のコメント/回答からI正解です)。たとえば、私のシステムでは、LINQPadを使用して、提供したコードがすぐに.で爆発しましたStackOverflowException

于 2012-12-29T21:12:54.723 に答える
-1

プログラムがVisualStudio環境で実行される場合、プログラムは限られたスタック深度を使用します。つまり、キーボードでF5とF6を押してVS2012でプログラムをコンパイルすると、csc.exeプログラムにいくつかのパラメーターが送信され、プログラムが制限され、スタックオーバーフローによってプログラムに含まれるバグが認識されます。ソースコードとアルゴリズム。実際には、スタックオーバーフローエラーは発生しません。プログラムのプロセスは実ストレージと仮想ストレージを使用し、OSが自動的に処理します。

注:これはOSにも関連しています。メモリ管理とCPUスケジューリングの弱点である場合、一部のOSはエラーをスローします。

于 2012-12-29T21:10:59.173 に答える