C言語解釈器-22補足:再帰的にStackOverflowExceptionを引き起こす
3372 ワード
複数の再帰呼び出しに含まれる次のテストCコードを実行する場合:
StackOverflowExceptionエラーが発生します.これは、デフォルトのスタックサイズが1 Mなので、すぐに消費されます.
解決策:
1.再帰の代わりに循環を使用します.
2.より小さい回数の再帰を使用します.
3.SharpCを修正し、適任させる.
明らかに1,2は考慮されていない.
SharpCは以下の変更が可能です.
まず大きなスタックサイズを設定し、SharpCで:
プログラムのスタックを設定できないため、別のスレッドしか開くことができません.
また、FunctionDefine.csでパラメータを保存して復元する方法は間違っています.正しい方法は、それらを注釈することです.
今では大再帰が可能になりました.
テストコードを実行し続け、65535回再帰し、512回ごとに再帰結果を出力します.実行結果は次のとおりです.
...
void fork2(int a, int b)
{
if ((a + b) % 1024 == 0)
print("iterate fork2: a=%i, b=%i
", a, b);
if (a + b == 2)
return;
else
fork2(--a, --b);
}
...
void main()
{
...
fork2(65535, 65535);
...
}
StackOverflowExceptionエラーが発生します.これは、デフォルトのスタックサイズが1 Mなので、すぐに消費されます.
解決策:
1.再帰の代わりに循環を使用します.
2.より小さい回数の再帰を使用します.
3.SharpCを修正し、適任させる.
明らかに1,2は考慮されていない.
SharpCは以下の変更が可能です.
まず大きなスタックサイズを設定し、SharpCで:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;
namespace SharpC
{
using Grammar;
public class SharpC
{
// Static
static public int MaxStackSize = 1024 * 1024 * 512; // 512M
...
プログラムのスタックを設定できないため、別のスレッドしか開くことができません.
namespace SharpC
{
using Grammar;
public class SharpC
{
....
public void Run(bool forceReparsing = false)
{
if (!m_lastParsingResult || forceReparsing)
Parse();
if (m_context != null)
{
if (OnBeforeRun != null)
OnBeforeRun(this, m_context);
(new System.Threading.Thread(delegate() {
try
{
IsRunning = true;
m_context.Run(m_context);
}
finally
{
IsRunning = false;
if (OnAfterRun != null)
OnAfterRun(this, m_context);
}
}, MaxStackSize)).Start();
}
}
....
また、FunctionDefine.csでパラメータを保存して復元する方法は間違っています.正しい方法は、それらを注釈することです.
namespace SharpC.Grammar.Function
{
public class FunctionDefine : Context
{
...
private void BeforeRun(Context ctx, List<Expression.Operand.Operand> parameters)
{
if (IsFirstRunning)
{
ConfigReturnEvent(ctx);
AllocateFixedArguments(ctx);
IsFirstRunning = false;
}
if (IsVariableArgument)
{
FreeVariableArgument(ctx);
AllocateVariableArguments(ctx, parameters);
}
//SavePreviousParameters(ctx);
InitArguments(ctx, parameters);
IteratorCount++;
}
....
private void AfterRun(Context ctx)
{
IteratorCount--;
if (IteratorCount > 0)
{
/*
if (m_parameterStack.Count > 0)
{
RestoreParameter(ctx);
}
*/
}
else
{
// Clean variable arguments
if (IsVariableArgument)
{
FreeVariableArgument(ctx);
}
}
}
...
今では大再帰が可能になりました.
テストコードを実行し続け、65535回再帰し、512回ごとに再帰結果を出力します.実行結果は次のとおりです.