【问题标题】:C# Process is Terminated due to StackOverFlowExceptionC# 进程因 StackOverFlowException 而终止
【发布时间】:2017-10-02 18:04:25
【问题描述】:

这是我的代码。运行时间会增加内存使用量,直到由于此错误而停止:

由于 StackOverFlowException 导致进程终止

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace KillWW
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting... {0} ", DateTime.Now);
            killWinword();
           // Console.Read();
        }

        private static void killWinword()
        {
            var procs = Process.GetProcesses();

            foreach (var proc in procs)
            {
                if (proc.ProcessName == "WINWORD")
                {
                    TimeSpan runtime;
                    runtime = DateTime.Now - proc.StartTime;

                    if (DateTime.Now > proc.StartTime.AddSeconds(20))
                    {
                        proc.Kill();
                    }
                }
            }

            Thread.Sleep(1000);
            killWinword();
        }
    }
}

谁能解释它的原因是什么?请帮我。谢谢。

【问题讨论】:

  • 你有一个没有停止条件的递归调用。所以这是一个无限递归。这将最终出现在 Stackoverflow 中。看来您想每秒进行一次检查。您可以使用计时器来执行此操作。
  • for-loop 中调用killWinword(); 有什么用?只需删除该语句
  • @SouvikGhosh 它不在 for 里面。
  • here 是使用 async/await 任务的解决方案。
  • @SouvikGhosh 我猜他试图让它每秒重复检查。他似乎没有意识到递归的副作用......

标签: c#


【解决方案1】:

KillWinWord 的最后一行正在调用自身。所以每一秒(在睡眠之后)你都会在堆栈上添加一个新层。

如果您希望 kill 功能永远持续下去,请将递归调用替换为 while 循环。

【讨论】:

  • 不过,这会阻塞主线程。不确定这在这里是否重要。
【解决方案2】:

你有一个没有停止条件的递归调用。 (killWinword 调用killWinword,后者调用killWinword ...)

所以这是一个无限递归。每个新调用都会占用更多的堆栈空间。这迟早会出现在 Stackoverflow 中。

您似乎想每秒进行一次检查。你可以:

  • 使用Timer 每秒滴答一次。
  • 使用任务和异步/等待(见Example
  • 使用普通的旧线程循环执行检查,这样您的主线程就不会被阻塞。

(没有特定的顺序。我个人会选择 async/await,但其他解决方案也适用于这个简单而简短的程序)。

Timer 的警告是您必须检查最后一次调用是否仍在运行。 Task 的优点是可以轻松使用线程池。

例子:

    // Run-Flag to gracefully exit loop.
    private static volatile bool _keepRunning = true;
    private static ManualResetEvent _exitRequest = new ManualResetEvent(false);
    static void Main(string[] args)
    {
        Console.WriteLine("Starting... {0} ", DateTime.Now);
        Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
            e.Cancel = true;
            MainClass._keepRunning = false;
        };            

        Task.Run(() => KillWinword); // Start Task on ThreadPool
        //You don't want to use Console.Read(); So ... wait for Ctrl-C?
        _exitRequest.WaitOne();
    }

    private static async Task KillWinword()
    {
        try
        {
            // Loop instead of recursion
            while(_keepRunning)
            {
                // Do your checks here
                DoKillWinword();

                // Don't delay if exit is requested.
                if(_keepRunning) await Task.Delay(1000);
            }
        }
        finally 
        {
        _exitRequest.Set();
        }
    }

    private static void DoKillWinword()
    {
        // TIPP: You should add some Exception handling in here!

        var procs = Process.GetProcesses();

        foreach (var proc in procs)
        {
            if (proc.ProcessName == "WINWORD")
            {
                TimeSpan runtime;
                runtime = DateTime.Now - proc.StartTime;

                if (DateTime.Now > proc.StartTime.AddSeconds(20))
                {
                    proc.Kill();
                }
            }
        }
    }

请注意,这不会准确地每秒开始检查。它将在前一个检查完成后 1 秒开始新的检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    • 2019-01-04
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 1970-01-01
    • 2014-11-18
    相关资源
    最近更新 更多