由于StackOverFlowException,C#进程终止

时间:2017-10-02 06:56:29

标签: c#

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

  

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

有人能解释一下它的原因是什么吗?请帮我。感谢。

2 个答案:

答案 0 :(得分:3)

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

如果您希望kill功能永久持续,请使用while循环替换递归调用。

答案 1 :(得分:0)

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

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

似乎你想每秒都做一次检查。你可以:

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

(没有具体的订单。我个人会去异步/等待,但其他解决方案也适用于这个简单的短程序。)

计时器的警告是你必须检查最后一次调用是否仍在运行。 Task的优点是您可以轻松使用Threadpool。

示例:

    // 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秒开始新的检查。