简体   繁体   English

由于 StackOverFlowException,C# 进程被终止

[英]C# Process is Terminated due to StackOverFlowException

This is my code.这是我的代码。 Running time increases memory usage until it stops due to this error:运行时间会增加内存使用量,直到由于此错误而停止:

Process is terminated due to StackOverFlowException由于 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();
        }
    }
}

Can someone explain what the cause of it is?有人可以解释它的原因是什么吗? Please help me.请帮我。 Thanks.谢谢。

Last line of KillWinWord is calling itself. KillWinWord 的最后一行在调用自己。 So each second (after the sleep) you add a new layer on the stack.所以每一秒(在睡眠之后)你都会在堆栈上添加一个新层。

If you want the kill feature to last forever, replace the recursive call by a while loop.如果您希望 kill 功能永远持续下去,请用 while 循环替换递归调用。

You have a recursive call without stop condition.您有一个没有停止条件的递归调用。 ( killWinword calls killWinword , which calls killWinword ... ) killWinword调用killWinword ,它调用killWinword ... )

So it's an infinite recursion.所以这是一个无限递归。 Each new call will take up more space on the stack.每个新调用都会在堆栈上占用更多空间。 This will sooner or later end up in Stackoverflow.这迟早会出现在 Stackoverflow 中。

It seems you want to do a check every second.看来您想每秒检查一次。 You can:你可以:

  • Use a Timer that ticks every second.使用每秒滴答一次的计时器
  • Use a Task and async/await ( See Example )使用 Task 和 async/await(见示例
  • Use a plain old Thread to execute the check in a loop, so your main Thread won't get blocked.使用普通的旧线程在循环中执行检查,因此您的主线程不会被阻塞。

(No specific order. I'd personally go for async/await but the other solutions are also valid for this simple and short program). (没有特定的顺序。我个人会选择 async/await,但其他解决方案也适用于这个简单而简短的程序)。

Caveat of Timer would be that you'd have to check if the last invocation is still running. Timer 的警告是您必须检查最后一次调用是否仍在运行。 Advantage of Task is you can easily make use of the Threadpool. Task 的优点是您可以轻松使用线程池。

Example:例子:

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

Mind that this will not exactly start the check every second.请注意,这不会每秒钟都准确地开始检查。 It will start a new check 1 second after the previous one is done.它将在前一个检查完成后 1 秒开始新的检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM