0

我有一个主要将字符串记录到文本文件的类库。它的方法之一是 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;
        }

    }
4

13 回答 13

9

这甚至看起来都不是递归函数。我不明白这会如何导致堆栈溢出。

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

于 2009-02-10T01:54:01.413 回答
3

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

于 2009-02-10T01:57:46.133 回答
2

@Franci Penov 提供了很好的建议
请阅读Raymond Chen 的这篇文章
它巧妙地解释了为什么堆栈溢出异常指向的函数不是罪魁祸首。

于 2009-02-10T04:13:09.660 回答
1

如果你真的想找到你的罪魁祸首,你需要在调用堆栈中再深入一点,看看它上面还有哪些其他函数。更准确地说,寻找重复的痕迹。

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

于 2009-02-10T02:46:32.363 回答
0

您是在问是否会导致 stackoverflow 或为什么会导致 stackoverflow?

Stackoverflows(通常)在递归出现轻微错误时发生。

于 2009-02-10T02:05:59.060 回答
0

响应OP 的更新:问题可能出在调用者方法上,而不是LogString()本身。如果调用者方法确实是递归方法,那么如果分配的堆栈大小不够大,肯定存在堆栈溢出的风险。

于 2009-02-10T02:06:57.810 回答
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)

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

* 不完全是,但足够接近。

于 2009-02-10T02:07:04.440 回答
0

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

于 2009-02-10T02:10:55.803 回答
0

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

    public bool filePathFilenameExists()
    {
        if (File.Exists(filePathFilename))
        {
            return true;
        }
        else
        {
           MessageBox.Show("Can not open Existing File.");
           return false;
        }
    }
于 2009-02-10T02:17:55.710 回答
0
    public bool filePathFilenameExists()
    {
        if (File.Exists(filePathFilename))
        {
            return true;
        }
        else
        {
           MessageBox.Show("Can not open Existing File.");
           return false;
        }
    }
于 2009-02-10T02:19:26.097 回答
0

这里还有一些有趣的地方,因为您发布的代码基本上不可能导致堆栈溢出。

  • 抛出堆栈溢出异常时,调用堆栈的其余部分是什么样的?
  • filePathFileName字段还是属性?如果它是一个属性,你是否在你的吸气剂中做任何事情?也许LogString(String)再打电话?
于 2009-02-10T02:46:43.160 回答
0

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

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

抛开理论不谈,假设从某个地方重复调用它,LogString 的输出应该会明显看出您的问题。那并在 IDE 调试器中查看您的堆栈。

于 2009-02-10T03:41:00.270 回答
0

谢谢大家的投入,对喧嚣感到抱歉。这是我的错,因为我的程序有我不知道的递归。我之所以没有发现这一点,是因为在程序停止之前我没有继续跟踪调用。当最后一次调用最后一个案例场景(最后一个函数)时,我总是停止调试,直到昨晚我继续调试直到程序自行停止然后我看到有很多调用来回进行,所以基于我的小编程经验我总结就是递归。

于 2009-02-12T21:02:09.537 回答