c# - मैं StackOverflowException को कैसे रोकूं और/या संभालूं?




.net stack-overflow (7)

नोट @ विलियमजॉकुश और मूल प्रश्न द्वारा बक्षीस में प्रश्न अलग हैं।

यह उत्तर तीसरे पक्ष के पुस्तकालयों के सामान्य मामले में स्टैक ओवरफ्लो के बारे में है और आप उनके साथ क्या कर सकते हैं / नहीं कर सकते हैं। यदि आप XslTransform के साथ विशेष मामले की तलाश में हैं, तो स्वीकृत उत्तर देखें।

ढेर ओवरफ्लो होते हैं क्योंकि स्टैक पर डेटा एक निश्चित सीमा (बाइट्स में) से अधिक है। इस पहचान कार्यों के बारे में विवरण here पाया जा सकता here

मैं सोच रहा हूं कि StackOverflowExceptions को ट्रैक करने का एक सामान्य तरीका है या नहीं। दूसरे शब्दों में, मान लीजिए कि मेरे कोड में कहीं भी अनंत रिकर्सन है, लेकिन मुझे पता नहीं है कि कहां है। मैं इसे किसी भी माध्यम से ट्रैक करना चाहता हूं जो पूरे स्थान पर कोड के माध्यम से कदम उठाने से आसान है जब तक कि मैं इसे नहीं देख पाता। मुझे परवाह नहीं है कि यह कितना हैकिश है।

जैसा कि मैंने लिंक में उल्लेख किया है, स्थिर कोड विश्लेषण से एक स्टैक ओवरफ़्लो का पता लगाने के लिए रोकथाम की समस्या को हल करने की आवश्यकता होगी जो अनावश्यक है । अब हमने पाया है कि कोई चांदी की बुलेट नहीं है , मैं आपको कुछ चाल दिखा सकता हूं जो मुझे लगता है कि समस्या को ट्रैक करने में मदद करता है।

मुझे लगता है कि इस सवाल को विभिन्न तरीकों से व्याख्या किया जा सकता है, और चूंकि मैं थोड़ा ऊब गया हूं :-), मैं इसे अलग-अलग बदलावों में तोड़ दूंगा।

एक परीक्षण वातावरण में एक ढेर ओवरफ्लो का पता लगाना

असल में यहां समस्या यह है कि आपके पास एक (सीमित) परीक्षण वातावरण है और एक (विस्तारित) उत्पादन वातावरण में एक स्टैक ओवरफ़्लो का पता लगाना चाहता है।

एसओ स्वयं का पता लगाने के बजाय, मैं इस तथ्य का शोषण करके इसे हल करता हूं कि ढेर गहराई को सेट किया जा सकता है। डीबगर आपको आवश्यक सारी जानकारी देगा। अधिकांश भाषाएं आपको स्टैक आकार या अधिकतम रिकर्सन गहराई निर्दिष्ट करने की अनुमति देती हैं।

असल में मैं स्टैक गहराई को जितना संभव हो उतना छोटा बनाकर एसओ को मजबूर करने की कोशिश करता हूं। यदि यह अतिप्रवाह नहीं होता है, तो मैं उत्पादन वातावरण के लिए इसे हमेशा बड़ा कर सकता हूं (= इस मामले में: सुरक्षित)। जिस क्षण आपको स्टैक ओवरफ़्लो मिलता है, आप मैन्युअल रूप से यह तय कर सकते हैं कि यह 'मान्य' है या नहीं।

ऐसा करने के लिए, स्टैक आकार (हमारे मामले में: एक छोटा मान) को थ्रेड पैरामीटर पर पास करें, और देखें कि क्या होता है। .NET में डिफ़ॉल्ट स्टैक आकार 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 पकड़ने योग्य नहीं है। इसका मतलब यह है कि ऐसा होने पर आप ऐसा नहीं कर सकते हैं। इसलिए, अगर आपको लगता है कि आपके कोड में कुछ गलत होना है, तो आप कुछ मामलों में अपना अपवाद बना सकते हैं। इसके लिए आपको केवल एक चीज की आवश्यकता है जो मौजूदा ढेर गहराई है; काउंटर की कोई आवश्यकता नहीं है, आप वास्तविक मूल्यों का उपयोग .NET से कर सकते हैं:

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();
    }
}

ध्यान दें कि यह दृष्टिकोण भी काम करता है यदि आप कॉलबैक तंत्र का उपयोग करने वाले तृतीय-पक्ष घटकों से निपट रहे हैं। केवल एक चीज की आवश्यकता है कि आप स्टैक ट्रेस में कुछ कॉल को रोक सकते हैं।

एक अलग धागे में जांच

आपने स्पष्ट रूप से यह सुझाव दिया है, तो यह यहां जाता है।

आप एक एसओ को एक अलग थ्रेड में पहचानने का प्रयास कर सकते हैं .. लेकिन शायद यह आपको कोई अच्छा काम नहीं करेगा। संदर्भ स्विच प्राप्त करने से पहले, एक स्टैक ओवरफ़्लो तेज़ हो सकता है। इसका मतलब यह है कि यह तंत्र बिल्कुल विश्वसनीय नहीं है ... मैं वास्तव में इसका उपयोग करने की अनुशंसा नहीं करता । यद्यपि निर्माण करना मजेदार था, इसलिए यहां कोड है :-)

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();
                }
            }
        }
    }
}

इसे डीबगर में चलाएं और क्या होता है इसका मजा लें।

एक ढेर अतिप्रवाह की विशेषताओं का उपयोग करना

आपके प्रश्न का एक अन्य व्याख्या यह है: "कोड के टुकड़े कहां हैं जो संभावित रूप से स्टैक ओवरफ़्लो अपवाद का कारण बन सकते हैं?"। जाहिर है इसका उत्तर है: रिकर्सन के साथ सभी कोड। कोड के प्रत्येक टुकड़े के लिए, आप कुछ मैन्युअल विश्लेषण कर सकते हैं।

स्थैतिक कोड विश्लेषण का उपयोग करके इसे निर्धारित करना भी संभव है। इसके लिए आपको क्या करने की ज़रूरत है सभी विधियों को कम करने और यह पता लगाने के लिए कि क्या उनमें अनंत रिकर्सन है। यहां कुछ कोड दिया गया है जो आपके लिए करता है:

// 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>());
        }
    }

अब, तथ्य यह है कि एक विधि चक्र में रिकर्सन होता है, इसका कोई मतलब नहीं है कि एक स्टैक ओवरफ़्लो होगा - यह आपके स्टैक ओवरफ़्लो अपवाद के लिए सबसे अधिक संभावना पूर्व शर्त है। संक्षेप में, इसका मतलब यह है कि यह कोड कोड के टुकड़े निर्धारित करेगा जहां एक स्टैक ओवरफ़्लो हो सकता है, जो अधिकतर कोड को काफी कम करना चाहिए।

फिर भी अन्य दृष्टिकोण

कुछ अन्य दृष्टिकोण हैं जिन्हें आप आजमा सकते हैं कि मैंने यहां वर्णित नहीं किया है।

  1. सीएलआर प्रक्रिया की मेजबानी करके और इसे संभालने के द्वारा स्टैक ओवरफ़्लो को संभालना। ध्यान दें कि आप अभी भी इसे पकड़ नहीं सकते हैं।
  2. सभी आईएल कोड बदलना, एक और डीएलएल बनाना, रिकर्सन पर चेक जोड़ना। हां, यह काफी संभव है (मैंने इसे अतीत में लागू किया है :-); यह मुश्किल है और इसे सही करने के लिए बहुत सारे कोड शामिल हैं।
  3. सभी विधि कॉल कैप्चर करने के लिए .NET प्रोफाइलिंग API का उपयोग करें और स्टैक ओवरफ़्लो को समझने के लिए इसका उपयोग करें। उदाहरण के लिए, आप चेक लागू कर सकते हैं कि यदि आप अपने कॉल पेड़ में एक ही विधि X बार सामना करते हैं, तो आप एक संकेत देते हैं। यहां एक परियोजना here जो आपको एक प्रमुख शुरुआत देगी।

मैं या तो StackOverflowException को रोक या संभालना चाहता हूं जिसे मैं XslCompiledTransform पर कॉल से प्राप्त कर रहा हूं। एक एक्सएसएल संपादक के भीतर ट्रांसफॉर्म विधि मैं लिख रहा हूं। समस्या यह प्रतीत होती है कि उपयोगकर्ता एक एक्सएसएल स्क्रिप्ट लिख सकता है जो अनन्त रूप से रिकर्सिव है, और यह सिर्फ ट्रांसफॉर्म विधि पर कॉल पर उड़ाता है। (यानी, समस्या केवल सामान्य प्रोग्रामेटिक त्रुटि नहीं है, जो आमतौर पर इस तरह के अपवाद का कारण है।)

क्या कितने रिकर्सन की अनुमति है इसका पता लगाने और / या सीमित करने का कोई तरीका है? या इस कोड को सिर्फ मुझ पर उड़ने से रखने के लिए कोई अन्य विचार?


.NET 4.0 के साथ आप System.Runtime.ExceptionServices से HandleProcessCorruptedStateExceptions गुण जोड़ सकते हैं जिसमें विधि / प्रयास ब्लॉक शामिल है। यह वास्तव में काम किया! शायद अनुशंसित नहीं है लेकिन काम करता है।

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

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

        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.();
                test.AccessViolation();
                //test.CustomException();
            }
            catch
            {
                Console.WriteLine("Caught.");
            }

            Console.WriteLine("End of program");

        }

    }      
}

आप इस संपत्ति को प्रत्येक कुछ कॉल, Environment.StackTrace । स्टैकट्रेस को पढ़ सकते हैं, और यदि स्टैक्र्रेस आपके द्वारा प्रीसेट किए गए विशिष्ट थ्रेसहोल्ड से अधिक हो जाता है, तो आप फ़ंक्शन वापस कर सकते हैं।

आपको लूप के साथ कुछ रिकर्सिव फ़ंक्शंस को प्रतिस्थापित करने का भी प्रयास करना चाहिए।


इसकी प्रकृति के अनुसार, एक और प्रक्रिया शुरू करने के अलावा, Exception को संभालने का कोई तरीका नहीं प्रतीत होता है। किसी और से पूछने से पहले, मैंने AppDomain का उपयोग करने की कोशिश की, लेकिन यह काम नहीं किया:

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

namespace ExceptionAppDomainTest
{
    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 Exception 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.Exited Process.StandardOutput और अपने उपयोगकर्ताओं को बेहतर अनुभव देने के लिए स्वयं त्रुटियों को संभालें।


मेरे पास आज एक स्टैक ओवरफ्लो था और मैंने आपकी कुछ पोस्ट पढ़ी और कचरा कलेक्टर की मदद करने का फैसला किया।

मैं इस तरह के करीब अनंत लूप होता था:

    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 
            }
        }
    }

इसके बजाए संसाधन इस तरह के दायरे से बाहर निकलने दें:

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
}

यह मेरे लिए काम करता है, उम्मीद है कि यह किसी की मदद करेगा।


मैं XmlWriter ऑब्जेक्ट के चारों ओर एक रैपर बनाने का सुझाव दूंगा, इसलिए यह WriteStartElement / WriteEndElement को कॉल की मात्रा की गणना करेगा, और यदि आप कुछ संख्या (फी 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 के लिए है।

मैं सोच रहा हूं कि Exceptions को ट्रैक करने का एक सामान्य तरीका है या नहीं। दूसरे शब्दों में, मान लीजिए कि मेरे कोड में कहीं भी अनंत रिकर्सन है, लेकिन मुझे पता नहीं है कि कहां है। मैं इसे किसी भी माध्यम से ट्रैक करना चाहता हूं जो पूरे स्थान पर कोड के माध्यम से कदम उठाने से आसान है जब तक कि मैं इसे नहीं देख पाता। मुझे परवाह नहीं है कि यह कितना हैकिश है। उदाहरण के लिए, एक मॉड्यूल रखना बहुत अच्छा होगा, शायद मैं किसी अन्य थ्रेड से भी सक्रिय हो सकता हूं, जिसने स्टैक गहराई को दबाया और शिकायत की अगर वह उस स्तर तक पहुंच गया जिसे मैंने "बहुत अधिक" माना। उदाहरण के लिए, मैं 600 फ्रेम तक "बहुत अधिक" सेट कर सकता हूं, यह पता लगा सकता हूं कि अगर ढेर बहुत गहरे थे, तो यह एक समस्या होनी चाहिए। ऐसा कुछ ऐसा संभव है। एक और उदाहरण डीबग आउटपुट में मेरे कोड के भीतर प्रत्येक 1000 वें विधि कॉल को लॉग करना होगा। संभावना है कि ओवरलैलो का कुछ सबूत बहुत अच्छा होगा, और यह संभवतः आउटपुट को बहुत बुरी तरह नहीं उड़ाएगा। कुंजी यह है कि जहां भी अतिप्रवाह हो रहा है, वहां एक चेक लिखना शामिल नहीं हो सकता है। क्योंकि पूरी समस्या यह है कि मुझे नहीं पता कि वह कहां है। पसंदीदा रूप से समाधान इस बात पर निर्भर नहीं होना चाहिए कि मेरा विकास पर्यावरण कैसा दिखता है; यानी, यह नहीं माना जाना चाहिए कि मैं एक विशिष्ट टूलसेट (उदाहरण के लिए वीएस) के माध्यम से सी # का उपयोग कर रहा हूं।

ऐसा लगता है कि आप इस स्टैक ओवरफ्लो को पकड़ने के लिए कुछ डीबगिंग तकनीकों को सुनना चाहते हैं, इसलिए मैंने सोचा कि मैं आपके लिए एक जोड़े को कोशिश करने के लिए साझा करूंगा।

1. मेमोरी डंप।

प्रो : मेमोरी डंप स्टैक ओवरफ़्लो के कारण को काम करने के लिए एक निश्चित अग्नि मार्ग है। एसी # एमवीपी और मैंने एक एसओ की समस्या निवारण के साथ काम किया और वह here इसके बारे में ब्लॉग करने गया।

समस्या को ट्रैक करने का यह तरीका सबसे तेज़ तरीका है।

इस विधि में आपको लॉग में देखे गए चरणों का पालन करके समस्याओं का पुनरुत्पादन करने की आवश्यकता नहीं है।

कॉन : मेमोरी डंप बहुत बड़े हैं और आपको प्रक्रिया को एडप्लस / procdump संलग्न करना होगा।

2. उम्मीदवार अभिविन्यास प्रोग्रामिंग।

प्रो : यह आपके लिए कोड को कार्यान्वित करने का सबसे आसान तरीका है जो आपके आवेदन की हर विधि में कोड लिखने के बिना किसी भी विधि से कॉल स्टैक के आकार की जांच करता है। एओपी फ्रेमवर्क का एक गुच्छा है जो आपको कॉल के पहले और बाद में इंटरसेप्ट करने की अनुमति देता है।

आपको उन तरीकों को बताएगा जो स्टैक ओवरफ़्लो का कारण बन रहे हैं।

आपको अपने आवेदन में सभी विधियों के प्रवेश और निकास पर StackTrace().FrameCount जांच करने की अनुमति देता है।

कॉन : इसका प्रदर्शन प्रभाव होगा - हुक को प्रत्येक विधि के लिए आईएल में एम्बेड किया गया है और आप वास्तव में इसे "डी-एक्टिवेट" नहीं कर सकते हैं।

यह कुछ हद तक आपके विकास पर्यावरण उपकरण सेट पर निर्भर करता है।

3. उपयोगकर्ता गतिविधि लॉगिंग।

एक हफ्ते पहले मैं समस्याओं को पुन: उत्पन्न करने के लिए कई कठिन शिकार करने की कोशिश कर रहा था। मैंने इस क्यूए उपयोगकर्ता गतिविधि लॉगिंग, टेलीमेट्री (और वैश्विक अपवाद हैंडलर में चर) पोस्ट किया । जिस निष्कर्ष पर मैं आया था, वह वास्तव में सरल उपयोगकर्ता-क्रिया-लॉगर था, यह देखने के लिए कि किसी भी अनचाहे अपवाद होने पर डीबगर में समस्याओं को पुन: उत्पन्न कैसे किया जाए।

प्रो : आप इसे इच्छानुसार चालू या बंद कर सकते हैं (यानी घटनाओं की सदस्यता लेना)।

उपयोगकर्ता क्रियाओं को ट्रैक करने के लिए हर विधि को अवरुद्ध करने की आवश्यकता नहीं होती है।

आप एओपी के मुकाबले कहीं ज्यादा आसानी से घटनाओं की संख्या की सदस्यता ले सकते हैं।

लॉग फाइलें अपेक्षाकृत छोटी हैं और समस्या को पुन: पेश करने के लिए आपको कौन सी कार्रवाइयों की आवश्यकता है, इस पर ध्यान केंद्रित करें।

यह आपको यह समझने में सहायता कर सकता है कि उपयोगकर्ता आपके एप्लिकेशन का उपयोग कैसे कर रहे हैं।

कॉन : विंडोज सेवा के लिए उपयुक्त नहीं है और मुझे यकीन है कि वेब ऐप्स के लिए इस तरह के बेहतर टूल हैं

आवश्यक रूप से आपको उन विधियों को नहीं बताता है जो स्टैक ओवरफ़्लो का कारण बनती हैं।

आपको मेमोरी डंप की बजाय समस्याओं को मैन्युअल रूप से पुन: उत्पन्न करने के लिए लॉग के माध्यम से कदम उठाने की आवश्यकता होती है जहां आप इसे प्राप्त कर सकते हैं और इसे सीधे डीबग कर सकते हैं।

हो सकता है कि आप उपर्युक्त सभी तकनीकों का प्रयास कर सकें और कुछ जिन्हें @atlaste पोस्ट किया गया है और हमें बताएं कि आपको कौन सा मिला है, प्रोड पर्यावरण / आदि में चलाने के लिए सबसे आसान / तेज़ / गंदे / सबसे स्वीकार्य था।

वैसे भी शुभकामनाएं इस एसओ को ट्रैक कर रही हैं।







xslcompiledtransform