문제

내가 좋아하거나 방지하거나 처리 StackOverflowException 나는 점점에서 호출하여 XslCompiledTransform.Transform 방법 내에서 Xsl Editor I am writing.문제는 것 같은 사용자가 작성 Xsl script 는 것은 무한히 재귀,그리고 다만 불면에서 호출 Transform 방법입니다.(즉,문제는 그냥 일반적인 프로그래밍 오류가,일반적으로 원인의 그러한 예외는 아니다.)

하는 방법이 있을 검출 그리고/또는 제한이 얼마나 많은 recursions 는 허용되나요?또 다른 아이디어를 계속 이 코드에서 초당 미터에까?

도움이 되었습니까?

해결책

Microsoft에서 :

.NET Framework 버전 2.0을 시작으로 StackoverFlowException 객체는 Try-Catch 블록으로 잡을 수 없으며 해당 프로세스는 기본적으로 종료됩니다. 결과적으로 사용자는 스택 오버플로를 감지하고 방지하기 위해 코드를 작성하는 것이 좋습니다. 예를 들어, 응용 프로그램이 재귀에 의존하는 경우 카운터 또는 상태 조건을 사용하여 재귀 루프를 종료하십시오.

코드가 아닌 내부 .NET 메소드 내에서 예외가 발생한다고 가정합니다.

당신은 몇 가지를 할 수 있습니다.

  • XSL을 무한 재귀를 확인하고 변환 (UGH)을 적용하기 전에 사용자에게 알리는 코드를 작성하십시오.
  • xsltransform 코드를 별도의 프로세스 (해킹하지만 더 적은 작업)에로드하십시오.

프로세스 클래스를 사용하여 변환을 별도의 프로세스에 적용하는 어셈블리를로드하고 메인 앱을 죽이지 않고 사망하면 실패를 사용자에게 알릴 수 있습니다.

편집 : 방금 테스트했습니다. 다음 방법은 다음과 같습니다.

메인 프로세스 :

// This is just an example, obviously you'll want to pass args to this.
Process p1 = new Process();
p1.StartInfo.FileName = "ApplyTransform.exe";
p1.StartInfo.UseShellExecute = false;
p1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

p1.Start();
p1.WaitForExit();

if (p1.ExitCode == 1)    
   Console.WriteLine("StackOverflow was thrown");

ApplyTransform 프로세스 :

class Program
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        throw new StackOverflowException();
    }

    // We trap this, we can't save the process, 
    // but we can prevent the "ILLEGAL OPERATION" window 
    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        if (e.IsTerminating)
        {
            Environment.Exit(1);
        }
    }
}

다른 팁

참고 질문에는 현상금 by@WilliamJockusch 와 원래의 질문은 다릅니다.

이에 대한 답변은 유래에서의 일반적인 케이스의 타사 라이브러리고 당신이 무엇을 할 수 있/을 할 수 없습니다.당신에 대해 특별한 경우로 XslTransform 참조하십시오 허용되는 대답이다.


스 오버플로우 발생하기 때문에 데이터를 스택에서 일정 한도를 초과(바이트 단위).의 세부 사항을 어떻게 이 검색은 작품을 찾을 수 있습니다 .

는지 궁금하네요가 있는 경우가 일반적인 방법으로 추적하 StackOverflowExceptions.다시 말해서,한 두 가지가 아닌 무한한 재귀에서 어딘가에 나의 코드,하지만 나는 아무 생각이 없다.내가 원하는 그 어떤 방법으로 쉽게 단계별 코드를 통해 모든 장소를 볼 때까지 그것은 일어나고 있다.나는 걱정하지 않는 방법 hackish 입니다.

에서 언급했듯이 링크를 검출 스택에서 오버플로 정적 분석 코드를 필요로 해결을 중단하는 문제입 써 undecidable.이제는 우리가 설립 이 없버, 에,나는 당신을 보여줄 수 있다는 몇 가지 요령이 생각 도움을 추적하는 문제입니다.

내가 생각하는 이 질문을 해석할 수 있는 다른 방법으로,그 이후로 저는 좀 지루해:-),내가 그것으로 다른 변형이 있습니다.

검출 스택에서는 오버플로 테스트 환경

기본적으로 문제가 여기에는(제한적)환경 테스트하고 싶은 감지 스택에서 오버플로우에는(확장)생산 환경이다.

대신 검 그래서 자체 해결이는다는 사실을 이용하여 스택을 깊이 설정할 수 있습니다.디버거를 줄 것이다 당신은 모든 정보를 확인할 수 있습니다.대부분의 언어로 지정할 수 있는 스택 크기 또는 최대 깊이.

기본적으로 나도 그렇게 만들어 스택을 깊이만큼 작은 가능합니다.지 않으면 오버플로,나는 항상 그것은 더 큰(=이 경우는 다음과 같습니다.안전)생산을 위한 환경입니다.는 순간 당신은 stack overflow,당신 수동으로 결정하면 그것은'유효한'하나하지 않습니다.

이를 통과 스택 크기(에서 우리의 경우:작은 값)스레드를 매개변수,그리고 어떻게 볼 것입니다.기본 스택 크기입니다.순이 1 메가바이트,우리가 사용하는 방법은 작은 값:

class StackOverflowDetector
{
    static int Recur()
    {
        int variable = 1;
        return variable + Recur();
    }

    static void Start()
    {
        int depth = 1 + Recur();
    }

    static void Main(string[] args)
    {
        Thread t = new Thread(Start, 1);
        t.Start();
        t.Join();
        Console.WriteLine();
        Console.ReadLine();
    }
}

참고:우리가 이 코드를 사용하려면 아래 뿐만 아니라.

그것은 오버플로,당신은 그것을 설정할 수 있습니다 더 큰 값을 얻을 때까지 그래서 그 의미가 있습니다.

예외 만들기 전에 당신이 그렇

StackOverflowException 지 않 잡을.이미 많지 않을 때 당신이 할 수있는 일이 일어났습니다.그래서,당신이 무언가를 믿는 경우에는 바인딩을 가 잘못된 코드에서,당신은 당신의 자신의 예외는 경우가 있습니다.만 필요한 것은 이것은 현재 stack depth;할 필요가 없을 위한 카운터를 사용할 수 있습니다 실제 가치를습니다.순:

class StackOverflowDetector
{
    static void CheckStackDepth()
    {
        if (new StackTrace().FrameCount > 10) // some arbitrary limit
        {
            throw new StackOverflowException("Bad thread.");
        }
    }

    static int Recur()
    {
        CheckStackDepth();
        int variable = 1;
        return variable + Recur();
    }

    static void Main(string[] args)
    {
        try
        {
            int depth = 1 + Recur();
        }
        catch (ThreadAbortException e)
        {
            Console.WriteLine("We've been a {0}", e.ExceptionState);
        }
        Console.WriteLine();
        Console.ReadLine();
    }
}

참고 또한 이러한 접근법을 작동하는 경우 다루고 있는 제삼자를 사용하는 구성 요소는 callback 메커니즘이 있습니다.만 필요한 것은 당신을 가로챌 수 있습니다 에서 호출 스택을 추적합니다.

검색에 별도의 스레드

당신이 명시적으로 제안이,그래서 여기에는 이 하나입니다.

당신이 시도할 수 있습을 검출하는,그래서 별도의 thread..하지만 그것은 아마도 당신에게 아무 소용 없이 좋다.Stack overflow 가 발생할 수 있습 fast, 하기도 전에,당신은 컨텍스트 스위치입니다.즉,이 메커니즘이지에서 신뢰할 수 있는 모든... 나는 권장하지 않습니다 실제로 그것을 사용하여.그것은 재미있는 구축을 하지만,그래서 여기에 코드:-)

class StackOverflowDetector
{
    static int Recur()
    {
        Thread.Sleep(1); // simulate that we're actually doing something :-)
        int variable = 1;
        return variable + Recur();
    }

    static void Start()
    {
        try
        {
            int depth = 1 + Recur();
        }
        catch (ThreadAbortException e)
        {
            Console.WriteLine("We've been a {0}", e.ExceptionState);
        }
    }

    static void Main(string[] args)
    {
        // Prepare the execution thread
        Thread t = new Thread(Start);
        t.Priority = ThreadPriority.Lowest;

        // Create the watch thread
        Thread watcher = new Thread(Watcher);
        watcher.Priority = ThreadPriority.Highest;
        watcher.Start(t);

        // Start the execution thread
        t.Start();
        t.Join();

        watcher.Abort();
        Console.WriteLine();
        Console.ReadLine();
    }

    private static void Watcher(object o)
    {
        Thread towatch = (Thread)o;

        while (true)
        {
            if (towatch.ThreadState == System.Threading.ThreadState.Running)
            {
                towatch.Suspend();
                var frames = new System.Diagnostics.StackTrace(towatch, false);
                if (frames.FrameCount > 20)
                {
                    towatch.Resume();
                    towatch.Abort("Bad bad thread!");
                }
                else
                {
                    towatch.Resume();
                }
            }
        }
    }
}

이에 디버거와 재미가 무엇이 발생합니다.

사용 특성 stack overflow

다른 해석을 당신의 질문은:"어디에 있는 조각의 코드는 잠재적으로 발생할 수 있습 stack overflow 예외?".분명히 대답이다:모든 코드와 재귀.각각의 코드로 다음을 수행할 수 있습니다 다음 몇 가지 설명서 분석합니다.

그것은 또한 가능한 이를 확인하려면 사용하는 코드는 정적 분석입니다.무엇을 할 필요가 있는 디컴파일 모든 방법 및 그 밖으로 포함하는 경우에는 무한한 재귀.여기에는 코드는 당신을 위해:

// A simple decompiler that extracts all method tokens (that is: call, callvirt, newobj in IL)
internal class Decompiler
{
    private Decompiler() { }

    static Decompiler()
    {
        singleByteOpcodes = new OpCode[0x100];
        multiByteOpcodes = new OpCode[0x100];
        FieldInfo[] infoArray1 = typeof(OpCodes).GetFields();
        for (int num1 = 0; num1 < infoArray1.Length; num1++)
        {
            FieldInfo info1 = infoArray1[num1];
            if (info1.FieldType == typeof(OpCode))
            {
                OpCode code1 = (OpCode)info1.GetValue(null);
                ushort num2 = (ushort)code1.Value;
                if (num2 < 0x100)
                {
                    singleByteOpcodes[(int)num2] = code1;
                }
                else
                {
                    if ((num2 & 0xff00) != 0xfe00)
                    {
                        throw new Exception("Invalid opcode: " + num2.ToString());
                    }
                    multiByteOpcodes[num2 & 0xff] = code1;
                }
            }
        }
    }

    private static OpCode[] singleByteOpcodes;
    private static OpCode[] multiByteOpcodes;

    public static MethodBase[] Decompile(MethodBase mi, byte[] ildata)
    {
        HashSet<MethodBase> result = new HashSet<MethodBase>();

        Module module = mi.Module;

        int position = 0;
        while (position < ildata.Length)
        {
            OpCode code = OpCodes.Nop;

            ushort b = ildata[position++];
            if (b != 0xfe)
            {
                code = singleByteOpcodes[b];
            }
            else
            {
                b = ildata[position++];
                code = multiByteOpcodes[b];
                b |= (ushort)(0xfe00);
            }

            switch (code.OperandType)
            {
                case OperandType.InlineNone:
                    break;
                case OperandType.ShortInlineBrTarget:
                case OperandType.ShortInlineI:
                case OperandType.ShortInlineVar:
                    position += 1;
                    break;
                case OperandType.InlineVar:
                    position += 2;
                    break;
                case OperandType.InlineBrTarget:
                case OperandType.InlineField:
                case OperandType.InlineI:
                case OperandType.InlineSig:
                case OperandType.InlineString:
                case OperandType.InlineTok:
                case OperandType.InlineType:
                case OperandType.ShortInlineR:
                    position += 4;
                    break;
                case OperandType.InlineR:
                case OperandType.InlineI8:
                    position += 8;
                    break;
                case OperandType.InlineSwitch:
                    int count = BitConverter.ToInt32(ildata, position);
                    position += count * 4 + 4;
                    break;

                case OperandType.InlineMethod:
                    int methodId = BitConverter.ToInt32(ildata, position);
                    position += 4;
                    try
                    {
                        if (mi is ConstructorInfo)
                        {
                            result.Add((MethodBase)module.ResolveMember(methodId, mi.DeclaringType.GetGenericArguments(), Type.EmptyTypes));
                        }
                        else
                        {
                            result.Add((MethodBase)module.ResolveMember(methodId, mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments()));
                        }
                    }
                    catch { } 
                    break;


                default:
                    throw new Exception("Unknown instruction operand; cannot continue. Operand type: " + code.OperandType);
            }
        }
        return result.ToArray();
    }
}

class StackOverflowDetector
{
    // This method will be found:
    static int Recur()
    {
        CheckStackDepth();
        int variable = 1;
        return variable + Recur();
    }

    static void Main(string[] args)
    {
        RecursionDetector();
        Console.WriteLine();
        Console.ReadLine();
    }

    static void RecursionDetector()
    {
        // First decompile all methods in the assembly:
        Dictionary<MethodBase, MethodBase[]> calling = new Dictionary<MethodBase, MethodBase[]>();
        var assembly = typeof(StackOverflowDetector).Assembly;

        foreach (var type in assembly.GetTypes())
        {
            foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).OfType<MethodBase>())
            {
                var body = member.GetMethodBody();
                if (body!=null)
                {
                    var bytes = body.GetILAsByteArray();
                    if (bytes != null)
                    {
                        // Store all the calls of this method:
                        var calls = Decompiler.Decompile(member, bytes);
                        calling[member] = calls;
                    }
                }
            }
        }

        // Check every method:
        foreach (var method in calling.Keys)
        {
            // If method A -> ... -> method A, we have a possible infinite recursion
            CheckRecursion(method, calling, new HashSet<MethodBase>());
        }
    }

지금은,사실에는 방법이 사이클이 포함되 재귀,수단에 의해 보장 stack overflow 일이 일어날 것입니다-그것은 단지 대부분의 전제 조건에 대한 당신의 stack overflow 예외는 아니다.에서 짧은,이 말의 의미는 다음과 같습니다드 결정할 것입니다 조각의 코드 스 버 가 발생해야하는 좁은 아래 대부분의 코드입니다.

아직 다른 접근법

거기에 몇 가지 다른 접근을 시도할 수 있습니다 하지는 않았 여기에 설명되어 있습니다.

  1. 처리 stack overflow 호스팅하여 CLR 프로세스 및 처리습니다.참고 당신은 여전히 할 수없는'잡을'니다.
  2. 변화하는 모든 IL 코드는,건물은 또 다른 DLL 추가,점검 재귀에.그래,그건 아주 가능(을 구현했 그것은 과거에:-);그것은 단지 어렵고 포함한 많은 코드가 바로 그것을 얻을 수 있습니다.
  3. 사용.NET 프로파일링 API 을 캡처하는 모든 메소드를 호출하고 사용하는 그 밖으로 stack overflow.예를 들어,구현할 수 있는지 확인합가 발생한 경우에는 동일한 방법 X 시간에 전화를 나,당신은 신호를 줄.있는 프로젝트 을 줄 것이다 당신은 머리를 시작합니다.

XMLWriter 객체 주위에 래퍼를 작성하는 것이 좋습니다. 따라서 writestArtelement/writeDendelement에 대한 호출량을 계산하고 태그 양을 일부 숫자 (FE 100)로 제한하면 다른 예외를 던질 수 있습니다. 무효화.

대부분의 경우 문제를 해결해야합니다.

public class LimitedDepthXmlWriter : XmlWriter
{
    private readonly XmlWriter _innerWriter;
    private readonly int _maxDepth;
    private int _depth;

    public LimitedDepthXmlWriter(XmlWriter innerWriter): this(innerWriter, 100)
    {
    }

    public LimitedDepthXmlWriter(XmlWriter innerWriter, int maxDepth)
    {
        _maxDepth = maxDepth;
        _innerWriter = innerWriter;
    }

    public override void Close()
    {
        _innerWriter.Close();
    }

    public override void Flush()
    {
        _innerWriter.Flush();
    }

    public override string LookupPrefix(string ns)
    {
        return _innerWriter.LookupPrefix(ns);
    }

    public override void WriteBase64(byte[] buffer, int index, int count)
    {
        _innerWriter.WriteBase64(buffer, index, count);
    }

    public override void WriteCData(string text)
    {
        _innerWriter.WriteCData(text);
    }

    public override void WriteCharEntity(char ch)
    {
        _innerWriter.WriteCharEntity(ch);
    }

    public override void WriteChars(char[] buffer, int index, int count)
    {
        _innerWriter.WriteChars(buffer, index, count);
    }

    public override void WriteComment(string text)
    {
        _innerWriter.WriteComment(text);
    }

    public override void WriteDocType(string name, string pubid, string sysid, string subset)
    {
        _innerWriter.WriteDocType(name, pubid, sysid, subset);
    }

    public override void WriteEndAttribute()
    {
        _innerWriter.WriteEndAttribute();
    }

    public override void WriteEndDocument()
    {
        _innerWriter.WriteEndDocument();
    }

    public override void WriteEndElement()
    {
        _depth--;

        _innerWriter.WriteEndElement();
    }

    public override void WriteEntityRef(string name)
    {
        _innerWriter.WriteEntityRef(name);
    }

    public override void WriteFullEndElement()
    {
        _innerWriter.WriteFullEndElement();
    }

    public override void WriteProcessingInstruction(string name, string text)
    {
        _innerWriter.WriteProcessingInstruction(name, text);
    }

    public override void WriteRaw(string data)
    {
        _innerWriter.WriteRaw(data);
    }

    public override void WriteRaw(char[] buffer, int index, int count)
    {
        _innerWriter.WriteRaw(buffer, index, count);
    }

    public override void WriteStartAttribute(string prefix, string localName, string ns)
    {
        _innerWriter.WriteStartAttribute(prefix, localName, ns);
    }

    public override void WriteStartDocument(bool standalone)
    {
        _innerWriter.WriteStartDocument(standalone);
    }

    public override void WriteStartDocument()
    {
        _innerWriter.WriteStartDocument();
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        if (_depth++ > _maxDepth) ThrowException();

        _innerWriter.WriteStartElement(prefix, localName, ns);
    }

    public override WriteState WriteState
    {
        get { return _innerWriter.WriteState; }
    }

    public override void WriteString(string text)
    {
        _innerWriter.WriteString(text);
    }

    public override void WriteSurrogateCharEntity(char lowChar, char highChar)
    {
        _innerWriter.WriteSurrogateCharEntity(lowChar, highChar);
    }

    public override void WriteWhitespace(string ws)
    {
        _innerWriter.WriteWhitespace(ws);
    }

    private void ThrowException()
    {
        throw new InvalidOperationException(string.Format("Result xml has more than {0} nested tags. It is possible that xslt transformation contains an endless recursive call.", _maxDepth));
    }
}

이 답변은 @williamjockusch를위한 것입니다.

StackoverFlowExceptions를 추적하는 일반적인 방법이 있는지 궁금합니다. 다시 말해, 내 코드 어딘가에 무한 재귀가 있다고 가정하지만 어디에 있는지 모르겠습니다. 나는 그것이 일어나는 것을 볼 때까지 모든 곳에서 코드를 밟는 것보다 쉬운 방법으로 추적하고 싶습니다. 나는 그것이 얼마나 해킹되는지 상관하지 않습니다. 예를 들어, 다른 스레드에서도 활성화 할 수있는 모듈을 사용하여 스택 깊이를 폴링하고 "너무 높음"으로 간주되는 레벨에 도달하면 불만을 제기하는 것이 좋습니다. 예를 들어, "너무 높음"을 600 프레임으로 설정하여 스택이 너무 깊다면 문제가되어야한다고 생각합니다. 가능한 것과 비슷합니다. 또 다른 예는 내 코드 내에서 1000 번째 메소드 호출마다 디버그 출력에 로그인하는 것입니다. 이것이 오류의 증거를 얻을 가능성은 꽤 좋을 것이며, 출력을 너무 나쁘게 날려 버리지 않을 것입니다. 핵심은 오버플로가 발생하는 곳마다 수표를 작성할 수 없다는 것입니다. 전체 문제는 그것이 어디에 있는지 모른다는 것입니다. 선호하는 솔루션은 내 개발 환경이 어떻게 보이는지에 달려 있지 않아야합니다. 즉, 특정 도구 세트 (예 : VS)를 통해 C#을 사용하고 있다고 가정해서는 안됩니다.

이 stackoverflow를 잡을 수있는 디버깅 기술을 듣고 싶어하는 것 같습니다.

1. 메모리 덤프.

프로: 메모리 덤프는 스택 오버플로의 원인을 해결하는 확실한 화재 방법입니다. AC# MVP & 나는 함께 일하면서 블로그에 갔다. 여기.

이 방법은 문제를 추적하는 가장 빠른 방법입니다.

이 방법은 로그에서 볼 수있는 단계를 따라 문제를 재현 할 필요가 없습니다.

사기: 메모리 덤프는 매우 크며 프로세스를 Adplus/ProcDump를 첨부해야합니다.

2. 측면 지향 프로그래밍.

프로: 이것은 아마도 응용 프로그램의 모든 방법에서 코드를 작성하지 않고 모든 방법에서 통화 스택의 크기를 확인하는 코드를 구현하는 가장 쉬운 방법 일 것입니다. 무리가 있습니다 AOP 프레임 워크 이를 통해 전화 전후를 가로 채실 수 있습니다.

스택 오버플로를 일으키는 방법을 알려줍니다.

당신이 확인할 수 있습니다 StackTrace().FrameCount 응용 프로그램의 모든 방법의 항목 및 종료시.

사기: 그것은 성능에 영향을 미칩니다. 후크는 모든 방법에 대해 IL에 내장되어 있으며 실제로 그것을 "활성화"할 수는 없습니다.

다소 개발 환경 도구 세트에 따라 다릅니다.

3. 사용자 활동을 기록합니다.

일주일 전에 나는 문제를 재현하기 위해 몇 가지 어려운 것을 사냥하려고 노력했다. 이 QA를 게시했습니다 사용자 활동 로깅, 원격 측정 (및 글로벌 예외 처리기의 변수) . 내가 겪은 결론은 처리되지 않은 예외가 발생할 때 디버거에서 문제를 재현하는 방법을보기위한 정말 간단한 사용자-액션 로거였습니다.

프로: 당신은 마음대로 켜거나 끌 수 있습니다 (즉, 이벤트 가입).

사용자 작업을 추적해도 모든 방법을 가로 채지 않아도됩니다.

이벤트 수를 구독 할 수 있습니다. AOP보다 훨씬 더.

로그 파일은 비교적 작으며 문제를 재현하기 위해 수행 해야하는 작업에 중점을 둡니다.

사용자가 응용 프로그램을 사용하는 방법을 이해하는 데 도움이 될 수 있습니다.

사기: Windows 서비스에 적합하지 않습니다 그리고 웹 앱에 이와 같은 더 나은 도구가 있다고 확신합니다..

그렇지 않습니다 반드시 스택 오버플로를 일으키는 방법을 알려주십시오.

메모리 덤프가 아닌 문제를 수동으로 재현하고 바로 디버깅해야합니다.

 


어쩌면 내가 위에서 언급 한 모든 기술과 @atlaste가 게시 한 모든 기술을 시도하고 당신이 찾은 것이 가장 쉬운/가장 빠른/더러운/더러운/가장 먼저 가장 허용되는 것이 좋았습니다.

어쨌든 행운을 빕니다.

응용 프로그램이 3D-Party 코드 (XSL 스크립트)에 의존하는 경우 먼저 버그에서 버그에서 방어하려는 것이 좋습니다. 당신이 정말로 방어하고 싶다면, 나는 당신이 별도의 appdomains에서 외부 오류가 발생하기 쉬운 논리를 실행해야한다고 생각합니다. stackoverflowexception을 잡는 것은 좋지 않습니다.

이것을 확인하십시오 의문.

나는 오늘 Stackoverflow를 가지고 있었고 나는 당신의 게시물 중 일부를 읽고 쓰레기 콜렉터를 도와 주기로 결정했습니다.

나는 다음과 같은 거의 무한 루프를 가지고 있었다.

    class Foo
    {
        public Foo()
        {
            Go();
        }

        public void Go()
        {
            for (float i = float.MinValue; i < float.MaxValue; i+= 0.000000000000001f)
            {
                byte[] b = new byte[1]; // Causes stackoverflow
            }
        }
    }

대신 자원이 다음과 같은 범위가 부족하게하십시오.

class Foo
{
    public Foo()
    {
        GoHelper();
    }

    public void GoHelper()
    {
        for (float i = float.MinValue; i < float.MaxValue; i+= 0.000000000000001f)
        {
            Go();
        }
    }

    public void Go()
    {
        byte[] b = new byte[1]; // Will get cleaned by GC
    }   // right now
}

그것은 나를 위해 일했고, 누군가를 돕기를 바랍니다.

.NET 4.0을 사용하면 추가 할 수 있습니다 HandleProcessCorruptedStateExceptions System.Runtime.ExceptionServices의 속성 Try/Catch 블록이 포함 된 방법에 대한 속성. 이것은 정말 효과가있었습니다! 권장하지는 않았지만 작동합니다.

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.ExceptionServices;

namespace ExceptionCatching
{
    public class Test
    {
        public void StackOverflow()
        {
            StackOverflow();
        }

        public void CustomException()
        {
            throw new Exception();
        }

        public unsafe void AccessViolation()
        {
            byte b = *(byte*)(8762765876);
        }
    }

    class Program
    {
        [HandleProcessCorruptedStateExceptions]
        static void Main(string[] args)
        {
            Test test = new Test();
            try {
                //test.StackOverflow();
                test.AccessViolation();
                //test.CustomException();
            }
            catch
            {
                Console.WriteLine("Caught.");
            }

            Console.WriteLine("End of program");

        }

    }      
}

@WilliamJockusch, 내가 당신의 관심사를 올바르게 이해하면 수학적 관점에서 불가능합니다. 언제나 무한 재귀를 식별하여 중단 문제. 그것을 해결하려면 a 초 수성 알고리즘 (처럼 시행 및 오류가 발생합니다 예를 들어) 또는 할 수있는 기계 초콜릿 (예는 다음에 설명되어 있습니다 다음 섹션 - 미리보기로 사용할 수 있습니다 이 책).

실용적인 관점에서 볼 때 다음을 알아야합니다.

  • 주어진 시간에 얼마나 많은 스택 메모리가 남았는지
  • 특정 출력에 대해 주어진 시간에 재귀 방법이 필요한 스택 메모리의 양.

현재 기계를 사용하면 멀티 태스킹으로 인해이 데이터가 매우 변한적이고 작업을 수행하는 소프트웨어에 대해 들어 보지 못했습니다.

무언가가 불분명한지 알려주세요.

다른 과정을 시작하는 것 외에도 StackOverflowException. 다른 사람이 묻기 전에 사용해 보았습니다 AppDomain, 그러나 그것은 작동하지 않았습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;

namespace StackOverflowExceptionAppDomainTest
{
    class Program
    {
        static void recrusiveAlgorithm()
        {
            recrusiveAlgorithm();
        }
        static void Main(string[] args)
        {
            if(args.Length>0&&args[0]=="--child")
            {
                recrusiveAlgorithm();
            }
            else
            {
                var domain = AppDomain.CreateDomain("Child domain to test StackOverflowException in.");
                domain.ExecuteAssembly(Assembly.GetEntryAssembly().CodeBase, new[] { "--child" });
                domain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) =>
                {
                    Console.WriteLine("Detected unhandled exception: " + e.ExceptionObject.ToString());
                };
                while (true)
                {
                    Console.WriteLine("*");
                    Thread.Sleep(1000);
                }
            }
        }
    }
}

그러나 별도의 프로세스 솔루션을 사용하는 경우 사용하는 것이 좋습니다. Process.Exited 그리고 Process.StandardOutput 사용자에게 더 나은 경험을 제공하기 위해 오류를 직접 처리하십시오.

몇 번의 전화 마다이 속성을 읽을 수 있습니다. Environment.StackTrace 그리고 스택 트레이스가 사전 설정하는 특정 임계 값을 표시하면 함수를 반환 할 수 있습니다.

또한 재귀 함수를 루프로 교체해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top