Event Process.Exited在while循环中重新实例化后超过其对象生命
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Event Process.Exited在while循环中重新实例化后超过其对象生命相关的知识,希望对你有一定的参考价值。
我已经在我的代码中发现了一些我无法解释的行为,即使它工作正常,但没有完全理解正在发生的事情真的困扰着我。下面的脚本创建并运行记事本的n_total
进程,但每次只允许运行最多的n_cpus
记事本。在开始时,启动n_cpus
进程,其余只在一个或多个运行的记事本终止时才开始。用户可以通过关闭其触发事件Process.Exited的窗口来终止每个记事本进程。现在,在循环内部,变量p
被重新用于每次需要一个新的记事本时实例化类Process,并且每个对象p
都订阅了事件Process.Exited由p.Exited += p_Exited;
考虑我们有n_cpus = 3
并运行代码直到它生成那3个同时记事本。我希望只有最后一个实例p
才会触发事件,因为我重新使用p
和p.Exited
属于该对象,但是没有......无论我关闭什么记事本,事件都会被触发并出现一个新的记事本。这是怎么回事?是否有某种无对象的委托列表EventHandler会记住我创建的每个进程?
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
// Summary: generates processes for "n_total" notepads allowing for a maximum of "n_cpus"
// notepads at each time. Every time a notepad closes another appears until all are run.
// A single variable "p" instantiates the class "Process" and the event "p.Exited"
// updates the number of running processes "n_running".
static int n_running = 0; // number of notepads running each time
static void Main()
{
int n_cpus = 3;
int n_total = 3 * n_cpus;
int i_run = 0;
while (i_run < n_total) // Process generating routine until all are run
{
if (n_running < n_cpus) // Only a maximum of n_cpus running at each time
{
n_running++;
i_run++;
Process p = new Process(); // A new object per process
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c notepad.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.EnableRaisingEvents = true;
p.Exited += p_Exited; // Is this associated with a particular object "p", right?
p.Start();
}
else Thread.Sleep(1000); // Waits 1s before checking for new terminated processes
}
}
static private void p_Exited(object sender, EventArgs e)
{
n_running--; // Updates the number of active processes. Triggers new future processes
}
}
我想你可能在这里做了几个错误的假设:
变量不是对象,它们是对象的引用。将对象分配给变量(通过new或其他)时,您不是“替换”或以其他方式删除或删除该变量先前引用的对象。如果没有更多对前一个对象的引用,它可能会在某个时刻被垃圾收集,但该对象仍然存在,并且可能还有其他东西使它“活着”(通过包含对它的引用)。某些编译器优化甚至可能导致相反的情况发生:如果编译器确定该变量未被再次使用,则在引用它的变量超出范围之前,对象可能会收集垃圾。
事件模式可能是C#中“内存泄漏”的最大单一来源,因为许多开发人员都没有意识到,当您注册事件时,正在侦听的对象的生命周期现在已扩展到侦听器的生命周期(因为该对象)正在被监听,现在有一个对监听器的引用,这个引用导致垃圾收集器不收集对象)。由于您的p_Exited是静态的,因此在您取消注册事件之前,您创建的所有Process对象现在都是“rooted”(不会被垃圾回收)。
变量p被重新用于实例化Process类
你实际上甚至没有“重用”p变量。它在循环范围内声明,因此每次循环时,p实际上都是一个“全新的”变量。当涉及到闭包时(即使是C#语言团队got this wrong),这也是一个特别重要的区别。
操作系统似乎是为你做的,因为你通过EnableRaisingEvents = true
启用了事件。
看到:
- https://msdn.microsoft.com/en-us/library/system.diagnostics.process.exited#Remarks
- https://msdn.microsoft.com/en-us/library/system.diagnostics.process.enableraisingevents。
以上是关于Event Process.Exited在while循环中重新实例化后超过其对象生命的主要内容,如果未能解决你的问题,请参考以下文章
“main process exited, code=exited”错误解决办法
“main process exited, code=exited”错误解决办法
Azkaban Process exited with code 255
CenOS7.1 vncserver@:1.service: control process exited, code=exited status=2
centOS 7一个解决“network.service: control process exited, code=exited status=1”方法