这个简单的C#代码会导致堆栈溢出吗?

时间:2009-02-10 01:51:34

标签: c# stack-overflow

我有一个类库,主要将字符串记录到文本文件中。其中一个方法是LogString(string str)所以我只是想知道基于下面的函数,如果我多次调用它超过600次,是否会导致stackoverflow?

    public void LogString(string str)
    {  
        try
        {
            if (filePathFilenameExists())
            {
                using (StreamWriter strmWriter = new StreamWriter(filePathFilename, true))
                {
                    strmWriter.WriteLine(str);
                    strmWriter.Flush();
                    strmWriter.Close();
                }
            }
            else
            {
                MessageBox.Show("Unable to write to file");
            }
        }
        catch (Exception err)
        {
            string errMsg = err.Message;
        }

    }

13 个答案:

答案 0 :(得分:9)

这甚至不是一个递归函数。我不知道这会如何导致堆栈溢出。

为了溢出堆栈,您必须不断地从函数内调用函数。每次执行此操作时,更多堆栈空间用于在被调用函数返回时恢复调用函数。递归函数遇到了这个问题,因为它们需要存储同一函数状态的多个副本,每个递归级别一个。这也可能发生在相互递归的函数中(A调用B,B调用A)并且它可能更难检测,但我不认为这是这种情况。

答案 1 :(得分:3)

不,它不会导致堆栈溢出,但如果两个不同的线程尝试写入同一个文件,它可能会导致其他异常。如果需要,请考虑使用lock使其成为线程安全的。

答案 2 :(得分:2)

@Franci Penov offers good advice
请阅读this post by Raymond Chen 它巧妙地解释了为什么堆栈溢出异常指向的函数不是罪魁祸首。

答案 3 :(得分:1)

如果你真的想找到罪魁祸首,你需要在调用堆栈中查看一下,看看其他功能是什么。更确切地说,寻找重复的痕迹。

获得堆栈溢出异常的另一种方法是,如果您的代码在堆栈上分配大块内存。你碰巧在代码中的某个地方处理大型结构吗?

答案 4 :(得分:0)

您是否在询问是否它会导致堆栈溢出或为什么会导致堆栈溢出?

当递归稍有不对时,会发生Stackoverflows(通常)。

答案 5 :(得分:0)

回复OP's update:问题可能在于调用者方法,而不是LogString()本身。如果调用方法确实是一个递归方法,那么如果分配的堆栈大小不够大,肯定存在堆栈溢出的风险。

答案 6 :(得分:0)

调用此函数不会导致“堆栈溢出”。您只能通过递归调用自身的函数导致堆栈溢出。我将简要解释一下:

当您在程序中调用函数时,它会在“调用堆栈”上创建一个新条目。这包含有关当前函数,调用它的位置以及函数的局部变量的一些信息。正如我所说,这个条目是在你调用函数时创建的,但是当你从函数返回,抛出异常,或者只是让函数到达它的结尾时,系统会使用该信息返回到前一个执行点,然后从调用堆栈中删除该条目

所以,在你调用你的函数之前,你可能已经在堆栈中了:

.                           .
.                           .
.                           .
|                           |
+---------------------------+
| performComplexOperation() |
| return address            |
| local variables           |
| ...                       |
+---------------------------+

然后,您调用LogString函数:

.                           .
.                           .
.                           .
|                           |
+---------------------------+
| performComplexOperation() |
| return address            |
| local variables           |
| ...                       |
+---------------------------+
| LogString()               |
| return address            |
| local variables           |
| ...                       |
+---------------------------+

但在LogString完成后,代码将使用返回地址返回performComplexOperation。 LogString的条目将被删除:

.                           .
.                           .
.                           .
|                           |
+---------------------------+
| performComplexOperation() |
| return address            |
| local variables           |
| ...                       |
+---------------------------+
       (this is where
    LogString used to be)

在堆栈溢出中,堆栈上的条目占用的空间将超过您正在使用的语言*分配给堆栈的空间,并且程序将无法为您的函数创建条目'即将打电话。

*不完全,但足够接近。

答案 7 :(得分:0)

我能想到的唯一问题是,如果你在这个函数中有一些疯狂的东西,你没有列出 filePathFilenameExists()的代码

答案 8 :(得分:0)

这是Sean认为是递归的函数filePathFileNameExists。

    public bool filePathFilenameExists()
    {
        if (File.Exists(filePathFilename))
        {
            return true;
        }
        else
        {
           MessageBox.Show("Can not open Existing File.");
           return false;
        }
    }

答案 9 :(得分:0)

    public bool filePathFilenameExists()
    {
        if (File.Exists(filePathFilename))
        {
            return true;
        }
        else
        {
           MessageBox.Show("Can not open Existing File.");
           return false;
        }
    }

答案 10 :(得分:0)

其他一些很有趣,因为你发布的代码基本上没有办法导致堆栈溢出。

  • 当抛出堆栈溢出异常时,调用堆栈的其余部分是什么样的?
  • filePathFileName是字段还是属性?如果它是一个属性,你在吸气器中做了什么吗?或许再次致电LogString(String)

答案 11 :(得分:0)

我认为Paul Fisher是对的,但这是我的第一篇文章,我没有代表对他的回答发表评论。

我的话语中的理论相同;你的调用函数导致堆栈溢出。它将自身的副本推送到堆栈,直到距离末端相对较短的距离。在调用函数的某些“N-1”递归迭代中,LogString的堆栈深度足以导致溢出,因为您距离堆栈末尾的距离很短。 filePathFilenameExists()可能比调用函数中的大多数其他方法具有更深的最大堆栈,并且足以将LogString单独作为捕获异常的幸运者。

理论除了你的问题应该通过LogString的输出显而易见,假设它是从某个地方重复调用的。那并在IDE调试器中查看您的堆栈。

答案 12 :(得分:0)

感谢大家的投入,并为喧嚣感到抱歉。这是我的错,因为我的程序有递归,我不知道。之所以我没有找到,因为我没有继续跟踪调用,直到程序停止。我总是在最后一次调用最后一个案例(最后一个函数)的时候停止调试,直到昨晚我继续调试,直到程序停止了,然后我看到有很多调用是根据我的小编程来回进行的经验我得出的结论是递归。